From ef27a1ce6c3cdb6f08584e76fa0c012377cadc49 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Wed, 8 Nov 2017 19:21:36 -0800 Subject: [PATCH 01/15] use logger --- include/zot.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/zot.php b/include/zot.php index 0aa50ab92..40e303bf1 100644 --- a/include/zot.php +++ b/include/zot.php @@ -2010,8 +2010,7 @@ function update_imported_item($sender, $item, $orig, $uid, $tag_delivery) { // may have a different owner than the one being transmitted. if(($sender['hash'] != $orig['owner_xchan'] && $sender['hash'] != $orig['author_xchan']) && (! $tag_delivery)) { - /// @fixme shouldn't this be logger? - notice('sender is not owner or author'); + logger('sender is not owner or author'); return; } From a4588af0f8ef56734ad0a974838f9efeff342eff Mon Sep 17 00:00:00 2001 From: zotlabs Date: Sun, 21 Jan 2018 17:06:38 -0800 Subject: [PATCH 02/15] mod_search: fix the group by mess --- Zotlabs/Lib/Config.php | 4 ++-- Zotlabs/Module/Search.php | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Zotlabs/Lib/Config.php b/Zotlabs/Lib/Config.php index f9f22ba3a..c00b8efb6 100644 --- a/Zotlabs/Lib/Config.php +++ b/Zotlabs/Lib/Config.php @@ -142,9 +142,9 @@ class Config { /** - * @brief Returns a value directly from the database configuration storage. + * @brief Returns a record directly from the database configuration storage. * - * This function queries directly the database and bypasses the chached storage + * This function queries directly the database and bypasses the cached storage * from get_config($family, $key). * * @param string $family diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php index a572a5a42..504c0353f 100644 --- a/Zotlabs/Module/Search.php +++ b/Zotlabs/Module/Search.php @@ -165,40 +165,41 @@ class Search extends \Zotlabs\Web\Controller { if($load) { $r = null; - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $prefix = 'distinct on (created, mid)'; - $suffix = 'ORDER BY created DESC, mid'; - } else { - $prefix = 'distinct'; - $suffix = 'group by mid ORDER BY created DESC'; - } if(local_channel()) { - $r = q("SELECT $prefix mid, item.id as item_id, item.* from item + $r = q("SELECT mid, MAX(id) as item_id from item WHERE ((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = '' AND item.deny_gid = '' AND item_private = 0 ) OR ( item.uid = %d )) OR item.owner_xchan = '%s' ) $item_normal $sql_extra - $suffix $pager_sql ", + group by mid order by created desc $pager_sql ", intval(local_channel()), dbesc($sys['xchan_hash']) ); } if($r === null) { - $r = q("SELECT $prefix mid, item.id as item_id, item.* from item + $r = q("SELECT mid, MAX(id) as item_id from item WHERE (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = '' AND item.deny_gid = '' AND item_private = 0 ) and owner_xchan in ( " . stream_perms_xchans(($observer) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " )) $pub_sql ) OR owner_xchan = '%s') $item_normal $sql_extra - $suffix $pager_sql", + group by mid order by created desc $pager_sql", dbesc($sys['xchan_hash']) ); } + if($r) { + $str = ids_to_querystr($r,'item_id'); + $r = q("select *, id as item_id from item where id in ( " . $str . ") "); + } } else { $r = array(); } + + + + } if($r) { From c994f26dbd8151bd1e937dbb13d3ae416740fdd9 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Sun, 21 Jan 2018 18:11:04 -0800 Subject: [PATCH 03/15] preserve reverse date sort in mod_search after changes --- Zotlabs/Module/Search.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php index 504c0353f..4d35b59f3 100644 --- a/Zotlabs/Module/Search.php +++ b/Zotlabs/Module/Search.php @@ -190,7 +190,7 @@ class Search extends \Zotlabs\Web\Controller { } if($r) { $str = ids_to_querystr($r,'item_id'); - $r = q("select *, id as item_id from item where id in ( " . $str . ") "); + $r = q("select *, id as item_id from item where id in ( " . $str . ") order by created desc "); } } else { From 629c915f36a6b22d9eba24e2394198c71bcf9365 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Sun, 21 Jan 2018 23:30:08 -0800 Subject: [PATCH 04/15] ensure filter words are not empty --- include/items.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/include/items.php b/include/items.php index d0b9cffc9..b12ad1d85 100755 --- a/include/items.php +++ b/include/items.php @@ -3009,14 +3009,17 @@ function check_item_source($uid, $item) { $words = explode("\n",$r[0]['src_patt']); if($words) { foreach($words as $word) { - if(substr($word,0,1) === '#' && $tags) { + $w = trim($word); + if(! $w) + continue; + if(substr($w,0,1) === '#' && $tags) { foreach($tags as $t) - if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($word,1)) || (substr($word,1) === '*'))) + if((($t['ttype'] == TERM_HASHTAG) || ($t['ttype'] == TERM_COMMUNITYTAG)) && (($t['term'] === substr($w,1)) || (substr($w,1) === '*'))) return true; } - elseif((strpos($word,'/') === 0) && preg_match($word,$text)) + elseif((strpos($w,'/') === 0) && preg_match($w,$text)) return true; - elseif(stristr($text,$word) !== false) + elseif(stristr($text,$w) !== false) return true; } } From f85c6d76de5532e62f95de3f4d814109ea3472f9 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Mon, 22 Jan 2018 11:54:53 -0800 Subject: [PATCH 05/15] better notifications for edit post/comments which may have been originally posted long ago --- Zotlabs/Lib/Enotify.php | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php index a7b4f28e8..5cf4ec31d 100644 --- a/Zotlabs/Lib/Enotify.php +++ b/Zotlabs/Lib/Enotify.php @@ -794,6 +794,20 @@ class Enotify { : sprintf( t('commented on %s\'s post'), $item['owner']['xchan_name'])); } + $edit = false; + + if($item['edited'] > $item['created']) { + if($item['item_thread_top']) { + $itemem_text = sprintf( t('edited a post dated %s'), relative_date($item['created'])); + $edit = true; + } + else { + $itemem_text = sprintf( t('edited a comment dated %s'), relative_date($item['created'])); + $edit = true; + } + } + + // convert this logic into a json array just like the system notifications return array( @@ -801,7 +815,7 @@ class Enotify { 'name' => $item['author']['xchan_name'], 'url' => $item['author']['xchan_url'], 'photo' => $item['author']['xchan_photo_s'], - 'when' => relative_date($item['created']), + 'when' => relative_date(($edit)? $item['edited'] : $item['created']), 'class' => (intval($item['item_unseen']) ? 'notify-unseen' : 'notify-seen'), 'b64mid' => ((in_array($item['verb'], [ACTIVITY_LIKE, ACTIVITY_DISLIKE])) ? 'b64.' . base64url_encode($item['thr_parent']) : 'b64.' . base64url_encode($item['mid'])), 'notify_id' => 'undefined', From 5967360991cb3766a6517759369b6d6fd8563c61 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Mon, 22 Jan 2018 16:49:45 -0800 Subject: [PATCH 06/15] hubzilla issue #920 - unable to delete permission groups with space in name --- Zotlabs/Module/Settings/Permcats.php | 4 ++-- view/tpl/settings_permcats.tpl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Zotlabs/Module/Settings/Permcats.php b/Zotlabs/Module/Settings/Permcats.php index 336f69653..535399083 100644 --- a/Zotlabs/Module/Settings/Permcats.php +++ b/Zotlabs/Module/Settings/Permcats.php @@ -49,7 +49,7 @@ class Permcats { if(argc() > 2) - $name = argv(2); + $name = hex2bin(argv(2)); if(argc() > 3 && argv(3) === 'drop') { \Zotlabs\Lib\Permcat::delete(local_channel(),$name); @@ -70,7 +70,7 @@ class Permcats { if(($pc['name']) && ($name) && ($pc['name'] == $name)) $existing = $pc['perms']; if(! $pc['system']) - $permcats[$pc['name']] = $pc['localname']; + $permcats[bin2hex($pc['name'])] = $pc['localname']; } } diff --git a/view/tpl/settings_permcats.tpl b/view/tpl/settings_permcats.tpl index f6bb9b036..bbbd41669 100644 --- a/view/tpl/settings_permcats.tpl +++ b/view/tpl/settings_permcats.tpl @@ -50,7 +50,7 @@ {{foreach $permcats as $k => $v}} - + {{/foreach}} From 4cfd7b65fba13b86450730aabdd7f37ea8e2afa9 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Mon, 22 Jan 2018 20:07:08 -0800 Subject: [PATCH 07/15] siteinfo embellishments --- Zotlabs/Module/Siteinfo.php | 1 - include/network.php | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Zotlabs/Module/Siteinfo.php b/Zotlabs/Module/Siteinfo.php index fafd51f65..92ee78cc6 100644 --- a/Zotlabs/Module/Siteinfo.php +++ b/Zotlabs/Module/Siteinfo.php @@ -5,7 +5,6 @@ namespace Zotlabs\Module; class Siteinfo extends \Zotlabs\Web\Controller { function init() { -logger(print_r($_REQUEST,true)); if (argv(1) === 'json' || $_REQUEST['module_format'] === 'json') { $data = get_site_info(); json_return_and_die($data); diff --git a/include/network.php b/include/network.php index 79a8c6578..2ac430e82 100644 --- a/include/network.php +++ b/include/network.php @@ -1579,6 +1579,7 @@ function get_site_info() { $channels_active_halfyear_stat = intval(get_config('system','channels_active_halfyear_stat')); $channels_active_monthly_stat = intval(get_config('system','channels_active_monthly_stat')); $local_posts_stat = intval(get_config('system','local_posts_stat')); + $local_comments_stat = intval(get_config('system','local_comments_stat')); $hide_in_statistics = intval(get_config('system','hide_in_statistics')); $site_expire = intval(get_config('system', 'default_expire_days')); @@ -1612,13 +1613,14 @@ function get_site_info() { 'default_service_restrictions' => $service_class, 'locked_features' => $locked_features, 'admin' => $admin, - 'dbdriver' => DBA::$dba->getdriver(), + 'dbdriver' => DBA::$dba->getdriver() . ' ' . ((ACTIVE_DBTYPE == DBTYPE_POSTGRES) ? 'postgres' : 'mysql'), 'lastpoll' => get_config('system','lastpoll'), 'info' => (($site_info) ? $site_info : ''), 'channels_total' => $channels_total_stat, 'channels_active_halfyear' => $channels_active_halfyear_stat, 'channels_active_monthly' => $channels_active_monthly_stat, 'local_posts' => $local_posts_stat, + 'local_comments' => $local_comments_stat, 'hide_in_statistics' => $hide_in_statistics ]; From c034fab4da043aceca212270f0c00fec9492e78d Mon Sep 17 00:00:00 2001 From: zotlabs Date: Mon, 22 Jan 2018 20:59:33 -0800 Subject: [PATCH 08/15] annual license update --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 25c4bf1a3..03d45aca6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2010-2017 the Hubzilla Community +Copyright (c) 2010-2018 the Hubzilla Community All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy From 4b7947d98c0625cfc53b481e2240a275e48c0d19 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Tue, 23 Jan 2018 16:36:56 -0800 Subject: [PATCH 09/15] replace image cropping library --- Zotlabs/Module/Cover_photo.php | 12 +- Zotlabs/Module/Profile_photo.php | 21 +- library/cropper/cropper.css | 182 -- library/cropper/cropper.html | 228 -- library/cropper/cropper.js | 566 ----- library/cropper/cropper.uncompressed.js | 1331 ----------- library/cropper/lib/builder.js | 101 - library/cropper/lib/controls.js | 815 ------- library/cropper/lib/dragdrop.js | 915 -------- library/cropper/lib/effects.js | 958 -------- library/cropper/lib/prototype.js | 2006 ----------------- library/cropper/lib/scriptaculous.js | 47 - library/cropper/lib/slider.js | 283 --- library/cropper/lib/unittest.js | 383 ---- library/cropper/licence.txt | 12 - library/cropper/marqueeHoriz.gif | Bin 1125 -> 0 bytes library/cropper/marqueeVert.gif | Bin 1141 -> 0 bytes library/cropper/tests/castle.jpg | Bin 34429 -> 0 bytes library/cropper/tests/castleMed.jpg | Bin 50584 -> 0 bytes library/cropper/tests/example-Basic.htm | 106 - .../cropper/tests/example-CSS-Absolute.htm | 162 -- library/cropper/tests/example-CSS-Float.htm | 124 - .../cropper/tests/example-CSS-Relative.htm | 116 - .../cropper/tests/example-CoordsOnLoad.htm | 108 - .../tests/example-CoordsOnLoadWithRatio.htm | 109 - library/cropper/tests/example-Dimensions.htm | 225 -- .../cropper/tests/example-DynamicImage.htm | 203 -- library/cropper/tests/example-FixedRatio.htm | 104 - .../tests/example-MinimumDimensions.htm | 105 - .../cropper/tests/example-MinimumWidth.htm | 105 - library/cropper/tests/example-Preview.htm | 117 - library/cropper/tests/poppy.jpg | Bin 18338 -> 0 bytes library/cropper/tests/staticHTMLStructure.htm | 236 -- library/cropperjs | 1 + view/tpl/cropbody.tpl | 41 +- view/tpl/cropcover.tpl | 40 +- view/tpl/crophead.tpl | 7 +- 37 files changed, 54 insertions(+), 9715 deletions(-) delete mode 100644 library/cropper/cropper.css delete mode 100644 library/cropper/cropper.html delete mode 100644 library/cropper/cropper.js delete mode 100644 library/cropper/cropper.uncompressed.js delete mode 100644 library/cropper/lib/builder.js delete mode 100644 library/cropper/lib/controls.js delete mode 100644 library/cropper/lib/dragdrop.js delete mode 100644 library/cropper/lib/effects.js delete mode 100644 library/cropper/lib/prototype.js delete mode 100644 library/cropper/lib/scriptaculous.js delete mode 100644 library/cropper/lib/slider.js delete mode 100644 library/cropper/lib/unittest.js delete mode 100644 library/cropper/licence.txt delete mode 100644 library/cropper/marqueeHoriz.gif delete mode 100644 library/cropper/marqueeVert.gif delete mode 100644 library/cropper/tests/castle.jpg delete mode 100644 library/cropper/tests/castleMed.jpg delete mode 100644 library/cropper/tests/example-Basic.htm delete mode 100644 library/cropper/tests/example-CSS-Absolute.htm delete mode 100644 library/cropper/tests/example-CSS-Float.htm delete mode 100644 library/cropper/tests/example-CSS-Relative.htm delete mode 100644 library/cropper/tests/example-CoordsOnLoad.htm delete mode 100644 library/cropper/tests/example-CoordsOnLoadWithRatio.htm delete mode 100644 library/cropper/tests/example-Dimensions.htm delete mode 100644 library/cropper/tests/example-DynamicImage.htm delete mode 100644 library/cropper/tests/example-FixedRatio.htm delete mode 100644 library/cropper/tests/example-MinimumDimensions.htm delete mode 100644 library/cropper/tests/example-MinimumWidth.htm delete mode 100644 library/cropper/tests/example-Preview.htm delete mode 100644 library/cropper/tests/poppy.jpg delete mode 100644 library/cropper/tests/staticHTMLStructure.htm create mode 160000 library/cropperjs diff --git a/Zotlabs/Module/Cover_photo.php b/Zotlabs/Module/Cover_photo.php index 47bce6c2b..cfb513365 100644 --- a/Zotlabs/Module/Cover_photo.php +++ b/Zotlabs/Module/Cover_photo.php @@ -64,12 +64,12 @@ class Cover_photo extends \Zotlabs\Web\Controller { $image_id = substr($image_id,0,-2); } - - $srcX = $_POST['xstart']; - $srcY = $_POST['ystart']; - $srcW = $_POST['xfinal'] - $srcX; - $srcH = $_POST['yfinal'] - $srcY; - + + + $srcX = intval($_POST['xstart']); + $srcY = intval($_POST['ystart']); + $srcW = intval($_POST['xfinal']) - $srcX; + $srcH = intval($_POST['yfinal']) - $srcY; $r = q("select gender from profile where uid = %d and is_default = 1 limit 1", intval(local_channel()) diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php index 45a606d5f..3aa6aee79 100644 --- a/Zotlabs/Module/Profile_photo.php +++ b/Zotlabs/Module/Profile_photo.php @@ -1,10 +1,11 @@ - 2. - - 3. - - -Options - -ratioDim obj - The pixel dimensions to apply as a restrictive ratio, with properties x & y. -minWidth int - The minimum width for the select area in pixels. -minHeight int - The mimimum height for the select area in pixels. -maxWidth int - The maximum width for the select areas in pixels (if both minWidth & maxWidth set to same the width of the cropper will be fixed) -maxHeight int - The maximum height for the select areas in pixels (if both minHeight & maxHeight set to same the height of the cropper will be fixed) -displayOnInit int - Whether to display the select area on initialisation, only used when providing minimum width & height or ratio. -onEndCrop func - The callback function to provide the crop details to on end of a crop. -captureKeys boolean - Whether to capture the keys for moving the select area, as these can cause some problems at the moment. -onloadCoords obj - A coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area to display onload - -The callback function - -The callback function is a function that allows you to capture the crop co-ordinates when the user finished a crop movement, it is passed two arguments: - - * coords, obj, coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area. - * dimensions, obj, dimensions object with properities width & height; for the dimensions of the select area. - -An example function which outputs the crop values to form fields: -Display code as plain text -JavaScript: - - 1. - function onEndCrop( coords, dimensions ) { - 2. - $( 'x1' ).value = coords.x1; - 3. - $( 'y1' ).value = coords.y1; - 4. - $( 'x2' ).value = coords.x2; - 5. - $( 'y2' ).value = coords.y2; - 6. - $( 'width' ).value = dimensions.width; - 7. - $( 'height' ).value = dimensions.height; - 8. - } - -Basic interface - -This basic example will attach the cropper UI to the test image and return crop results to the provided callback function. -Display code as plain text -HTML: - - 1. - Test image - 2. - - 3. - - -Minimum dimensions - -You can apply minimum dimensions to a single axis or both, this example applies minimum dimensions to both axis. -Display code as plain text -HTML: - - 1. - Test image - 2. - - 3. - - -Select area ratio - -You can apply a ratio to the selection area, this example applies a 4:3 ratio to the select area. -Display code as plain text -HTML: - - 1. - Test image - 2. - - 3. - - -With crop preview - -You can display a dynamically prouced preview of the resulting crop by using the ImgWithPreview subclass, a preview can only be displayed when we have a fixed size (set via minWidth & minHeight options). Note that the displayOnInit option is not required as this is the default behaviour when displaying a crop preview. -Display code as plain text -HTML: - - 1. - Test image - 2. -
- 3. - - 4. - - -Known Issues - - * Safari animated gifs, only one of each will animate, this seems to be a known Safari issue. - * After drawing an area and then clicking to start a new drag in IE 5.5 the rendered height appears as the last height until the user drags, this appears to be the related to another IE error (which has been fixed) where IE does not always redraw the select area properly. - * Lack of CSS opacity support in Opera before version 9 mean we disable those style rules, if Opera 8 support is important you & you want the overlay to work then you can use the Opera rules in the CSS to apply a black PNG with 50% alpha transparency to replicate the effect. - * Styling & borders on image, any CSS styling applied directly to the image itself (floats, borders, padding, margin, etc.) will cause problems with the cropper. The use of a wrapper element to apply these styles to is recommended. - * overflow: auto or overflow: scroll on parent will cause cropper to burst out of parent in IE and Opera when applied (maybe Mac browsers too) I'm not sure why yet. - -If you use CakePHP you will notice that including this in your script will break the CSS layout. This is due to the CSS rule - -form div{ -vertical-align: text-top; -margin-left: 1em; -margin-bottom:2em; -overflow: auto; -} - -A simple workaround is to add another rule directly after this like so: - -form div.no_cake, form div.no_cake div { -margin:0; -overflow:hidden; -} - -and then in your code surround the img tag with a div with the class name of no_cake. - -Cheers - diff --git a/library/cropper/cropper.js b/library/cropper/cropper.js deleted file mode 100644 index 486a92ad9..000000000 --- a/library/cropper/cropper.js +++ /dev/null @@ -1,566 +0,0 @@ -/** - * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/) - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://www.opensource.org/licenses/bsd-license.php - * - * See scriptaculous.js for full scriptaculous licence - */ - -var CropDraggable=Class.create(); -Object.extend(Object.extend(CropDraggable.prototype,Draggable.prototype),{initialize:function(_1){ -this.options=Object.extend({drawMethod:function(){ -}},arguments[1]||{}); -this.element=$(_1); -this.handle=this.element; -this.delta=this.currentDelta(); -this.dragging=false; -this.eventMouseDown=this.initDrag.bindAsEventListener(this); -Event.observe(this.handle,"mousedown",this.eventMouseDown); -Draggables.register(this); -},draw:function(_2){ -var _3=Position.cumulativeOffset(this.element); -var d=this.currentDelta(); -_3[0]-=d[0]; -_3[1]-=d[1]; -var p=[0,1].map(function(i){ -return (_2[i]-_3[i]-this.offset[i]); -}.bind(this)); -this.options.drawMethod(p); -}}); -var Cropper={}; -Cropper.Img=Class.create(); -Cropper.Img.prototype={initialize:function(_7,_8){ -this.options=Object.extend({ratioDim:{x:0,y:0},minWidth:0,minHeight:0,displayOnInit:false,onEndCrop:Prototype.emptyFunction,captureKeys:true,onloadCoords:null,maxWidth:0,maxHeight:0},_8||{}); -this.img=$(_7); -this.clickCoords={x:0,y:0}; -this.dragging=false; -this.resizing=false; -this.isWebKit=/Konqueror|Safari|KHTML/.test(navigator.userAgent); -this.isIE=/MSIE/.test(navigator.userAgent); -this.isOpera8=/Opera\s[1-8]/.test(navigator.userAgent); -this.ratioX=0; -this.ratioY=0; -this.attached=false; -this.fixedWidth=(this.options.maxWidth>0&&(this.options.minWidth>=this.options.maxWidth)); -this.fixedHeight=(this.options.maxHeight>0&&(this.options.minHeight>=this.options.maxHeight)); -if(typeof this.img=="undefined"){ -return; -} -$A(document.getElementsByTagName("script")).each(function(s){ -if(s.src.match(/cropper\.js/)){ -var _a=s.src.replace(/cropper\.js(.*)?/,""); -var _b=document.createElement("link"); -_b.rel="stylesheet"; -_b.type="text/css"; -_b.href=_a+"cropper.css"; -_b.media="screen"; -document.getElementsByTagName("head")[0].appendChild(_b); -} -}); -if(this.options.ratioDim.x>0&&this.options.ratioDim.y>0){ -var _c=this.getGCD(this.options.ratioDim.x,this.options.ratioDim.y); -this.ratioX=this.options.ratioDim.x/_c; -this.ratioY=this.options.ratioDim.y/_c; -} -this.subInitialize(); -if(this.img.complete||this.isWebKit){ -this.onLoad(); -}else{ -Event.observe(this.img,"load",this.onLoad.bindAsEventListener(this)); -} -},getGCD:function(a,b){ -if(b==0){ -return a; -} -return this.getGCD(b,a%b); -},onLoad:function(){ -var _f="imgCrop_"; -var _10=this.img.parentNode; -var _11=""; -if(this.isOpera8){ -_11=" opera8"; -} -this.imgWrap=Builder.node("div",{"class":_f+"wrap"+_11}); -this.north=Builder.node("div",{"class":_f+"overlay "+_f+"north"},[Builder.node("span")]); -this.east=Builder.node("div",{"class":_f+"overlay "+_f+"east"},[Builder.node("span")]); -this.south=Builder.node("div",{"class":_f+"overlay "+_f+"south"},[Builder.node("span")]); -this.west=Builder.node("div",{"class":_f+"overlay "+_f+"west"},[Builder.node("span")]); -var _12=[this.north,this.east,this.south,this.west]; -this.dragArea=Builder.node("div",{"class":_f+"dragArea"},_12); -this.handleN=Builder.node("div",{"class":_f+"handle "+_f+"handleN"}); -this.handleNE=Builder.node("div",{"class":_f+"handle "+_f+"handleNE"}); -this.handleE=Builder.node("div",{"class":_f+"handle "+_f+"handleE"}); -this.handleSE=Builder.node("div",{"class":_f+"handle "+_f+"handleSE"}); -this.handleS=Builder.node("div",{"class":_f+"handle "+_f+"handleS"}); -this.handleSW=Builder.node("div",{"class":_f+"handle "+_f+"handleSW"}); -this.handleW=Builder.node("div",{"class":_f+"handle "+_f+"handleW"}); -this.handleNW=Builder.node("div",{"class":_f+"handle "+_f+"handleNW"}); -this.selArea=Builder.node("div",{"class":_f+"selArea"},[Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeNorth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeEast"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeHoriz "+_f+"marqueeSouth"},[Builder.node("span")]),Builder.node("div",{"class":_f+"marqueeVert "+_f+"marqueeWest"},[Builder.node("span")]),this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW,Builder.node("div",{"class":_f+"clickArea"})]); -this.imgWrap.appendChild(this.img); -this.imgWrap.appendChild(this.dragArea); -this.dragArea.appendChild(this.selArea); -this.dragArea.appendChild(Builder.node("div",{"class":_f+"clickArea"})); -_10.appendChild(this.imgWrap); -this.startDragBind=this.startDrag.bindAsEventListener(this); -Event.observe(this.dragArea,"mousedown",this.startDragBind); -this.onDragBind=this.onDrag.bindAsEventListener(this); -Event.observe(document,"mousemove",this.onDragBind); -this.endCropBind=this.endCrop.bindAsEventListener(this); -Event.observe(document,"mouseup",this.endCropBind); -this.resizeBind=this.startResize.bindAsEventListener(this); -this.handles=[this.handleN,this.handleNE,this.handleE,this.handleSE,this.handleS,this.handleSW,this.handleW,this.handleNW]; -this.registerHandles(true); -if(this.options.captureKeys){ -this.keysBind=this.handleKeys.bindAsEventListener(this); -Event.observe(document,"keypress",this.keysBind); -} -new CropDraggable(this.selArea,{drawMethod:this.moveArea.bindAsEventListener(this)}); -this.setParams(); -},registerHandles:function(_13){ -for(var i=0;i0&&this.options.ratioDim.y>0){ -_1a.x1=Math.ceil((this.imgW-this.options.ratioDim.x)/2); -_1a.y1=Math.ceil((this.imgH-this.options.ratioDim.y)/2); -_1a.x2=_1a.x1+this.options.ratioDim.x; -_1a.y2=_1a.y1+this.options.ratioDim.y; -_1b=true; -} -} -this.setAreaCoords(_1a,false,false,1); -if(this.options.displayOnInit&&_1b){ -this.selArea.show(); -this.drawArea(); -this.endCrop(); -} -this.attached=true; -},remove:function(){ -if(this.attached){ -this.attached=false; -this.imgWrap.parentNode.insertBefore(this.img,this.imgWrap); -this.imgWrap.parentNode.removeChild(this.imgWrap); -Event.stopObserving(this.dragArea,"mousedown",this.startDragBind); -Event.stopObserving(document,"mousemove",this.onDragBind); -Event.stopObserving(document,"mouseup",this.endCropBind); -this.registerHandles(false); -if(this.options.captureKeys){ -Event.stopObserving(document,"keypress",this.keysBind); -} -} -},reset:function(){ -if(!this.attached){ -this.onLoad(); -}else{ -this.setParams(); -} -this.endCrop(); -},handleKeys:function(e){ -var dir={x:0,y:0}; -if(!this.dragging){ -switch(e.keyCode){ -case (37): -dir.x=-1; -break; -case (38): -dir.y=-1; -break; -case (39): -dir.x=1; -break; -case (40): -dir.y=1; -break; -} -if(dir.x!=0||dir.y!=0){ -if(e.shiftKey){ -dir.x*=10; -dir.y*=10; -} -this.moveArea([this.areaCoords.x1+dir.x,this.areaCoords.y1+dir.y]); -Event.stop(e); -} -} -},calcW:function(){ -return (this.areaCoords.x2-this.areaCoords.x1); -},calcH:function(){ -return (this.areaCoords.y2-this.areaCoords.y1); -},moveArea:function(_1e){ -this.setAreaCoords({x1:_1e[0],y1:_1e[1],x2:_1e[0]+this.calcW(),y2:_1e[1]+this.calcH()},true,false); -this.drawArea(); -},cloneCoords:function(_1f){ -return {x1:_1f.x1,y1:_1f.y1,x2:_1f.x2,y2:_1f.y2}; -},setAreaCoords:function(_20,_21,_22,_23,_24){ -if(_21){ -var _25=_20.x2-_20.x1; -var _26=_20.y2-_20.y1; -if(_20.x1<0){ -_20.x1=0; -_20.x2=_25; -} -if(_20.y1<0){ -_20.y1=0; -_20.y2=_26; -} -if(_20.x2>this.imgW){ -_20.x2=this.imgW; -_20.x1=this.imgW-_25; -} -if(_20.y2>this.imgH){ -_20.y2=this.imgH; -_20.y1=this.imgH-_26; -} -}else{ -if(_20.x1<0){ -_20.x1=0; -} -if(_20.y1<0){ -_20.y1=0; -} -if(_20.x2>this.imgW){ -_20.x2=this.imgW; -} -if(_20.y2>this.imgH){ -_20.y2=this.imgH; -} -if(_23!=null){ -if(this.ratioX>0){ -this.applyRatio(_20,{x:this.ratioX,y:this.ratioY},_23,_24); -}else{ -if(_22){ -this.applyRatio(_20,{x:1,y:1},_23,_24); -} -} -var _27=[this.options.minWidth,this.options.minHeight]; -var _28=[this.options.maxWidth,this.options.maxHeight]; -if(_27[0]>0||_27[1]>0||_28[0]>0||_28[1]>0){ -var _29={a1:_20.x1,a2:_20.x2}; -var _2a={a1:_20.y1,a2:_20.y2}; -var _2b={min:0,max:this.imgW}; -var _2c={min:0,max:this.imgH}; -if((_27[0]!=0||_27[1]!=0)&&_22){ -if(_27[0]>0){ -_27[1]=_27[0]; -}else{ -if(_27[1]>0){ -_27[0]=_27[1]; -} -} -} -if((_28[0]!=0||_28[0]!=0)&&_22){ -if(_28[0]>0&&_28[0]<=_28[1]){ -_28[1]=_28[0]; -}else{ -if(_28[1]>0&&_28[1]<=_28[0]){ -_28[0]=_28[1]; -} -} -} -if(_27[0]>0){ -this.applyDimRestriction(_29,_27[0],_23.x,_2b,"min"); -} -if(_27[1]>1){ -this.applyDimRestriction(_2a,_27[1],_23.y,_2c,"min"); -} -if(_28[0]>0){ -this.applyDimRestriction(_29,_28[0],_23.x,_2b,"max"); -} -if(_28[1]>1){ -this.applyDimRestriction(_2a,_28[1],_23.y,_2c,"max"); -} -_20={x1:_29.a1,y1:_2a.a1,x2:_29.a2,y2:_2a.a2}; -} -} -} -this.areaCoords=_20; -},applyDimRestriction:function(_2d,val,_2f,_30,_31){ -var _32; -if(_31=="min"){ -_32=((_2d.a2-_2d.a1)val); -} -if(_32){ -if(_2f==1){ -_2d.a2=_2d.a1+val; -}else{ -_2d.a1=_2d.a2-val; -} -if(_2d.a1<_30.min){ -_2d.a1=_30.min; -_2d.a2=val; -}else{ -if(_2d.a2>_30.max){ -_2d.a1=_30.max-val; -_2d.a2=_30.max; -} -} -} -},applyRatio:function(_33,_34,_35,_36){ -var _37; -if(_36=="N"||_36=="S"){ -_37=this.applyRatioToAxis({a1:_33.y1,b1:_33.x1,a2:_33.y2,b2:_33.x2},{a:_34.y,b:_34.x},{a:_35.y,b:_35.x},{min:0,max:this.imgW}); -_33.x1=_37.b1; -_33.y1=_37.a1; -_33.x2=_37.b2; -_33.y2=_37.a2; -}else{ -_37=this.applyRatioToAxis({a1:_33.x1,b1:_33.y1,a2:_33.x2,b2:_33.y2},{a:_34.x,b:_34.y},{a:_35.x,b:_35.y},{min:0,max:this.imgH}); -_33.x1=_37.a1; -_33.y1=_37.b1; -_33.x2=_37.a2; -_33.y2=_37.b2; -} -},applyRatioToAxis:function(_38,_39,_3a,_3b){ -var _3c=Object.extend(_38,{}); -var _3d=_3c.a2-_3c.a1; -var _3e=Math.floor(_3d*_39.b/_39.a); -var _3f; -var _40; -var _41=null; -if(_3a.b==1){ -_3f=_3c.b1+_3e; -if(_3f>_3b.max){ -_3f=_3b.max; -_41=_3f-_3c.b1; -} -_3c.b2=_3f; -}else{ -_3f=_3c.b2-_3e; -if(_3f<_3b.min){ -_3f=_3b.min; -_41=_3f+_3c.b2; -} -_3c.b1=_3f; -} -if(_41!=null){ -_40=Math.floor(_41*_39.a/_39.b); -if(_3a.a==1){ -_3c.a2=_3c.a1+_40; -}else{ -_3c.a1=_3c.a1=_3c.a2-_40; -} -} -return _3c; -},drawArea:function(){ -var _42=this.calcW(); -var _43=this.calcH(); -var px="px"; -var _45=[this.areaCoords.x1+px,this.areaCoords.y1+px,_42+px,_43+px,this.areaCoords.x2+px,this.areaCoords.y2+px,(this.img.width-this.areaCoords.x2)+px,(this.img.height-this.areaCoords.y2)+px]; -var _46=this.selArea.style; -_46.left=_45[0]; -_46.top=_45[1]; -_46.width=_45[2]; -_46.height=_45[3]; -var _47=Math.ceil((_42-6)/2)+px; -var _48=Math.ceil((_43-6)/2)+px; -this.handleN.style.left=_47; -this.handleE.style.top=_48; -this.handleS.style.left=_47; -this.handleW.style.top=_48; -this.north.style.height=_45[1]; -var _49=this.east.style; -_49.top=_45[1]; -_49.height=_45[3]; -_49.left=_45[4]; -_49.width=_45[6]; -var _4a=this.south.style; -_4a.top=_45[5]; -_4a.height=_45[7]; -var _4b=this.west.style; -_4b.top=_45[1]; -_4b.height=_45[3]; -_4b.width=_45[0]; -this.subDrawArea(); -this.forceReRender(); -},forceReRender:function(){ -if(this.isIE||this.isWebKit){ -var n=document.createTextNode(" "); -var d,el,fixEL,i; -if(this.isIE){ -fixEl=this.selArea; -}else{ -if(this.isWebKit){ -fixEl=document.getElementsByClassName("imgCrop_marqueeSouth",this.imgWrap)[0]; -d=Builder.node("div",""); -d.style.visibility="hidden"; -var _4e=["SE","S","SW"]; -for(i=0;i<_4e.length;i++){ -el=document.getElementsByClassName("imgCrop_handle"+_4e[i],this.selArea)[0]; -if(el.childNodes.length){ -el.removeChild(el.childNodes[0]); -} -el.appendChild(d); -} -} -} -fixEl.appendChild(n); -fixEl.removeChild(n); -} -},startResize:function(e){ -this.startCoords=this.cloneCoords(this.areaCoords); -this.resizing=true; -this.resizeHandle=Event.element(e).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/,""); -Event.stop(e); -},startDrag:function(e){ -this.selArea.show(); -this.clickCoords=this.getCurPos(e); -this.setAreaCoords({x1:this.clickCoords.x,y1:this.clickCoords.y,x2:this.clickCoords.x,y2:this.clickCoords.y},false,false,null); -this.dragging=true; -this.onDrag(e); -Event.stop(e); -},getCurPos:function(e){ -var el=this.imgWrap,wrapOffsets=Position.cumulativeOffset(el); -while(el.nodeName!="BODY"){ -wrapOffsets[1]-=el.scrollTop||0; -wrapOffsets[0]-=el.scrollLeft||0; -el=el.parentNode; -} -return curPos={x:Event.pointerX(e)-wrapOffsets[0],y:Event.pointerY(e)-wrapOffsets[1]}; -},onDrag:function(e){ -if(this.dragging||this.resizing){ -var _54=null; -var _55=this.getCurPos(e); -var _56=this.cloneCoords(this.areaCoords); -var _57={x:1,y:1}; -if(this.dragging){ -if(_55.x_59){ -_5c.reverse(); -} -_5a[_5b+"1"]=_5c[0]; -_5a[_5b+"2"]=_5c[1]; -},endCrop:function(){ -this.dragging=false; -this.resizing=false; -this.options.onEndCrop(this.areaCoords,{width:this.calcW(),height:this.calcH()}); -},subInitialize:function(){ -},subDrawArea:function(){ -}}; -Cropper.ImgWithPreview=Class.create(); -Object.extend(Object.extend(Cropper.ImgWithPreview.prototype,Cropper.Img.prototype),{subInitialize:function(){ -this.hasPreviewImg=false; -if(typeof (this.options.previewWrap)!="undefined"&&this.options.minWidth>0&&this.options.minHeight>0){ -this.previewWrap=$(this.options.previewWrap); -this.previewImg=this.img.cloneNode(false); -this.previewImg.id="imgCrop_"+this.previewImg.id; -this.options.displayOnInit=true; -this.hasPreviewImg=true; -this.previewWrap.addClassName("imgCrop_previewWrap"); -this.previewWrap.setStyle({width:this.options.minWidth+"px",height:this.options.minHeight+"px"}); -this.previewWrap.appendChild(this.previewImg); -} -},subDrawArea:function(){ -if(this.hasPreviewImg){ -var _5d=this.calcW(); -var _5e=this.calcH(); -var _5f={x:this.imgW/_5d,y:this.imgH/_5e}; -var _60={x:_5d/this.options.minWidth,y:_5e/this.options.minHeight}; -var _61={w:Math.ceil(this.options.minWidth*_5f.x)+"px",h:Math.ceil(this.options.minHeight*_5f.y)+"px",x:"-"+Math.ceil(this.areaCoords.x1/_60.x)+"px",y:"-"+Math.ceil(this.areaCoords.y1/_60.y)+"px"}; -var _62=this.previewImg.style; -_62.width=_61.w; -_62.height=_61.h; -_62.left=_61.x; -_62.top=_61.y; -} -}}); - diff --git a/library/cropper/cropper.uncompressed.js b/library/cropper/cropper.uncompressed.js deleted file mode 100644 index 66185546e..000000000 --- a/library/cropper/cropper.uncompressed.js +++ /dev/null @@ -1,1331 +0,0 @@ -/** - * Image Cropper (v. 1.2.0 - 2006-10-30 ) - * Copyright (c) 2006 David Spurr (http://www.defusion.org.uk/) - * - * The image cropper provides a way to draw a crop area on an image and capture - * the coordinates of the drawn crop area. - * - * Features include: - * - Based on Prototype and Scriptaculous - * - Image editing package styling, the crop area functions and looks - * like those found in popular image editing software - * - Dynamic inclusion of required styles - * - Drag to draw areas - * - Shift drag to draw/resize areas as squares - * - Selection area can be moved - * - Seleciton area can be resized using resize handles - * - Allows dimension ratio limited crop areas - * - Allows minimum dimension crop areas - * - Allows maximum dimesion crop areas - * - If both min & max dimension options set to the same value for a single axis,then the cropper will not - * display the resize handles as appropriate (when min & max dimensions are passed for both axes this - * results in a 'fixed size' crop area) - * - Allows dynamic preview of resultant crop ( if minimum width & height are provided ), this is - * implemented as a subclass so can be excluded when not required - * - Movement of selection area by arrow keys ( shift + arrow key will move selection area by - * 10 pixels ) - * - All operations stay within bounds of image - * - All functionality & display compatible with most popular browsers supported by Prototype: - * PC: IE 7, 6 & 5.5, Firefox 1.5, Opera 8.5 (see known issues) & 9.0b - * MAC: Camino 1.0, Firefox 1.5, Safari 2.0 - * - * Requires: - * - Prototype v. 1.5.0_rc0 > (as packaged with Scriptaculous 1.6.1) - * - Scriptaculous v. 1.6.1 > modules: builder, dragdrop - * - * Known issues: - * - Safari animated gifs, only one of each will animate, this seems to be a known Safari issue - * - * - After drawing an area and then clicking to start a new drag in IE 5.5 the rendered height - * appears as the last height until the user drags, this appears to be the related to the error - * that the forceReRender() method fixes for IE 6, i.e. IE 5.5 is not redrawing the box properly. - * - * - Lack of CSS opacity support in Opera before version 9 mean we disable those style rules, these - * could be fixed by using PNGs with transparency if Opera 8.5 support is high priority for you - * - * - Marching ants keep reloading in IE <6 (not tested in IE7), it is a known issue in IE and I have - * found no viable workarounds that can be included in the release. If this really is an issue for you - * either try this post: http://mir.aculo.us/articles/2005/08/28/internet-explorer-and-ajax-image-caching-woes - * or uncomment the 'FIX MARCHING ANTS IN IE' rules in the CSS file - * - * - Styling & borders on image, any CSS styling applied directly to the image itself (floats, borders, padding, margin, etc.) will - * cause problems with the cropper. The use of a wrapper element to apply these styles to is recommended. - * - * - overflow: auto or overflow: scroll on parent will cause cropper to burst out of parent in IE and Opera (maybe Mac browsers too) - * I'm not sure why yet. - * - * Usage: - * See Cropper.Img & Cropper.ImgWithPreview for usage details - * - * Changelog: - * v1.2.0 - 2006-10-30 - * + Added id to the preview image element using 'imgCrop_[originalImageID]' - * * #00001 - Fixed bug: Doesn't account for scroll offsets - * * #00009 - Fixed bug: Placing the cropper inside differently positioned elements causes incorrect co-ordinates and display - * * #00013 - Fixed bug: I-bar cursor appears on drag plane - * * #00014 - Fixed bug: If ID for image tag is not found in document script throws error - * * Fixed bug with drag start co-ordinates if wrapper element has moved in browser (e.g. dragged to a new position) - * * Fixed bug with drag start co-ordinates if image contained in a wrapper with scrolling - this may be buggy if image - * has other ancestors with scrolling applied (except the body) - * * #00015 - Fixed bug: When cropper removed and then reapplied onEndCrop callback gets called multiple times, solution suggestion from Bill Smith - * * Various speed increases & code cleanup which meant improved performance in Mac - which allowed removal of different overlay methods for - * IE and all other browsers, which led to a fix for: - * * #00010 - Fixed bug: Select area doesn't adhere to image size when image resized using img attributes - * - #00006 - Removed default behaviour of automatically setting a ratio when both min width & height passed, the ratioDimensions must be passed in - * + #00005 - Added ability to set maximum crop dimensions, if both min & max set as the same value then we'll get a fixed cropper size on the axes as appropriate - * and the resize handles will not be displayed as appropriate - * * Switched keydown for keypress for moving select area with cursor keys (makes for nicer action) - doesn't appear to work in Safari - * - * v1.1.3 - 2006-08-21 - * * Fixed wrong cursor on western handle in CSS - * + #00008 & #00003 - Added feature: Allow to set dimensions & position for cropper on load - * * #00002 - Fixed bug: Pressing 'remove cropper' twice removes image in IE - * - * v1.1.2 - 2006-06-09 - * * Fixed bugs with ratios when GCD is low (patch submitted by Andy Skelton) - * - * v1.1.1 - 2006-06-03 - * * Fixed bug with rendering issues fix in IE 5.5 - * * Fixed bug with endCrop callback issues once cropper had been removed & reset in IE - * - * v1.1.0 - 2006-06-02 - * * Fixed bug with IE constantly trying to reload select area background image - * * Applied more robust fix to Safari & IE rendering issues - * + Added method to reset parameters - useful for when dynamically changing img cropper attached to - * + Added method to remove cropper from image - * - * v1.0.0 - 2006-05-18 - * + Initial verison - * - * - * Copyright (c) 2006, David Spurr (http://www.defusion.org.uk/) - * All rights reserved. - * - * - * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * http://www.opensource.org/licenses/bsd-license.php - * - * See scriptaculous.js for full scriptaculous licence - */ - -/** - * Extend the Draggable class to allow us to pass the rendering - * down to the Cropper object. - */ -var CropDraggable = Class.create(); - -Object.extend( Object.extend( CropDraggable.prototype, Draggable.prototype), { - - initialize: function(element) { - this.options = Object.extend( - { - /** - * The draw method to defer drawing to - */ - drawMethod: function() {} - }, - arguments[1] || {} - ); - - this.element = $(element); - - this.handle = this.element; - - this.delta = this.currentDelta(); - this.dragging = false; - - this.eventMouseDown = this.initDrag.bindAsEventListener(this); - Event.observe(this.handle, "mousedown", this.eventMouseDown); - - Draggables.register(this); - }, - - /** - * Defers the drawing of the draggable to the supplied method - */ - draw: function(point) { - var pos = Position.cumulativeOffset(this.element); - var d = this.currentDelta(); - pos[0] -= d[0]; - pos[1] -= d[1]; - - var p = [0,1].map(function(i) { - return (point[i]-pos[i]-this.offset[i]) - }.bind(this)); - - this.options.drawMethod( p ); - } - -}); - - -/** - * The Cropper object, this will attach itself to the provided image by wrapping it with - * the generated xHTML structure required by the cropper. - * - * Usage: - * @param obj Image element to attach to - * @param obj Optional options: - * - ratioDim obj - * The pixel dimensions to apply as a restrictive ratio, with properties x & y - * - * - minWidth int - * The minimum width for the select area in pixels - * - * - minHeight int - * The mimimum height for the select area in pixels - * - * - maxWidth int - * The maximum width for the select areas in pixels (if both minWidth & maxWidth set to same the width of the cropper will be fixed) - * - * - maxHeight int - * The maximum height for the select areas in pixels (if both minHeight & maxHeight set to same the height of the cropper will be fixed) - * - * - displayOnInit int - * Whether to display the select area on initialisation, only used when providing minimum width & height or ratio - * - * - onEndCrop func - * The callback function to provide the crop details to on end of a crop (see below) - * - * - captureKeys boolean - * Whether to capture the keys for moving the select area, as these can cause some problems at the moment - * - * - onloadCoords obj - * A coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area to display onload - * - *---------------------------------------------- - * - * The callback function provided via the onEndCrop option should accept the following parameters: - * - coords obj - * The coordinates object with properties x1, y1, x2 & y2; for the coordinates of the select area - * - * - dimensions obj - * The dimensions object with properites width & height; for the dimensions of the select area - * - * - * Example: - * function onEndCrop( coords, dimensions ) { - * $( 'x1' ).value = coords.x1; - * $( 'y1' ).value = coords.y1; - * $( 'x2' ).value = coords.x2; - * $( 'y2' ).value = coords.y2; - * $( 'width' ).value = dimensions.width; - * $( 'height' ).value = dimensions.height; - * } - * - */ -var Cropper = {}; -Cropper.Img = Class.create(); -Cropper.Img.prototype = { - - /** - * Initialises the class - * - * @access public - * @param obj Image element to attach to - * @param obj Options - * @return void - */ - initialize: function(element, options) { - this.options = Object.extend( - { - /** - * @var obj - * The pixel dimensions to apply as a restrictive ratio - */ - ratioDim: { x: 0, y: 0 }, - /** - * @var int - * The minimum pixel width, also used as restrictive ratio if min height passed too - */ - minWidth: 0, - /** - * @var int - * The minimum pixel height, also used as restrictive ratio if min width passed too - */ - minHeight: 0, - /** - * @var boolean - * Whether to display the select area on initialisation, only used when providing minimum width & height or ratio - */ - displayOnInit: false, - /** - * @var function - * The call back function to pass the final values to - */ - onEndCrop: Prototype.emptyFunction, - /** - * @var boolean - * Whether to capture key presses or not - */ - captureKeys: true, - /** - * @var obj Coordinate object x1, y1, x2, y2 - * The coordinates to optionally display the select area at onload - */ - onloadCoords: null, - /** - * @var int - * The maximum width for the select areas in pixels (if both minWidth & maxWidth set to same the width of the cropper will be fixed) - */ - maxWidth: 0, - /** - * @var int - * The maximum height for the select areas in pixels (if both minHeight & maxHeight set to same the height of the cropper will be fixed) - */ - maxHeight: 0 - }, - options || {} - ); - /** - * @var obj - * The img node to attach to - */ - this.img = $( element ); - /** - * @var obj - * The x & y coordinates of the click point - */ - this.clickCoords = { x: 0, y: 0 }; - /** - * @var boolean - * Whether the user is dragging - */ - this.dragging = false; - /** - * @var boolean - * Whether the user is resizing - */ - this.resizing = false; - /** - * @var boolean - * Whether the user is on a webKit browser - */ - this.isWebKit = /Konqueror|Safari|KHTML/.test( navigator.userAgent ); - /** - * @var boolean - * Whether the user is on IE - */ - this.isIE = /MSIE/.test( navigator.userAgent ); - /** - * @var boolean - * Whether the user is on Opera below version 9 - */ - this.isOpera8 = /Opera\s[1-8]/.test( navigator.userAgent ); - /** - * @var int - * The x ratio - */ - this.ratioX = 0; - /** - * @var int - * The y ratio - */ - this.ratioY = 0; - /** - * @var boolean - * Whether we've attached sucessfully - */ - this.attached = false; - /** - * @var boolean - * Whether we've got a fixed width (if minWidth EQ or GT maxWidth then we have a fixed width - * in the case of minWidth > maxWidth maxWidth wins as the fixed width) - */ - this.fixedWidth = ( this.options.maxWidth > 0 && ( this.options.minWidth >= this.options.maxWidth ) ); - /** - * @var boolean - * Whether we've got a fixed height (if minHeight EQ or GT maxHeight then we have a fixed height - * in the case of minHeight > maxHeight maxHeight wins as the fixed height) - */ - this.fixedHeight = ( this.options.maxHeight > 0 && ( this.options.minHeight >= this.options.maxHeight ) ); - - // quit if the image element doesn't exist - if( typeof this.img == 'undefined' ) return; - - // include the stylesheet - $A( document.getElementsByTagName( 'script' ) ).each( - function(s) { - if( s.src.match( /cropper\.js/ ) ) { - var path = s.src.replace( /cropper\.js(.*)?/, '' ); - // ''; - var style = document.createElement( 'link' ); - style.rel = 'stylesheet'; - style.type = 'text/css'; - style.href = path + 'cropper.css'; - style.media = 'screen'; - document.getElementsByTagName( 'head' )[0].appendChild( style ); - } - } - ); - - // calculate the ratio when neccessary - if( this.options.ratioDim.x > 0 && this.options.ratioDim.y > 0 ) { - var gcd = this.getGCD( this.options.ratioDim.x, this.options.ratioDim.y ); - this.ratioX = this.options.ratioDim.x / gcd; - this.ratioY = this.options.ratioDim.y / gcd; - // dump( 'RATIO : ' + this.ratioX + ':' + this.ratioY + '\n' ); - } - - // initialise sub classes - this.subInitialize(); - - // only load the event observers etc. once the image is loaded - // this is done after the subInitialize() call just in case the sub class does anything - // that will affect the result of the call to onLoad() - if( this.img.complete || this.isWebKit ) this.onLoad(); // for some reason Safari seems to support img.complete but returns 'undefined' on the this.img object - else Event.observe( this.img, 'load', this.onLoad.bindAsEventListener( this) ); - }, - - /** - * The Euclidean algorithm used to find the greatest common divisor - * - * @acces private - * @param int Value 1 - * @param int Value 2 - * @return int - */ - getGCD : function( a , b ) { - if( b == 0 ) return a; - return this.getGCD(b, a % b ); - }, - - /** - * Attaches the cropper to the image once it has loaded - * - * @access private - * @return void - */ - onLoad: function( ) { - /* - * Build the container and all related elements, will result in the following - * - *
- * - *
- * - *
- *
- *
- *
- *
- * - * - *
- *
- *
- *
- * - *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */ - var cNamePrefix = 'imgCrop_'; - - // get the point to insert the container - var insertPoint = this.img.parentNode; - - // apply an extra class to the wrapper to fix Opera below version 9 - var fixOperaClass = ''; - if( this.isOpera8 ) fixOperaClass = ' opera8'; - this.imgWrap = Builder.node( 'div', { 'class': cNamePrefix + 'wrap' + fixOperaClass } ); - - this.north = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'north' }, [Builder.node( 'span' )] ); - this.east = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'east' } , [Builder.node( 'span' )] ); - this.south = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'south' }, [Builder.node( 'span' )] ); - this.west = Builder.node( 'div', { 'class': cNamePrefix + 'overlay ' + cNamePrefix + 'west' } , [Builder.node( 'span' )] ); - - var overlays = [ this.north, this.east, this.south, this.west ]; - - this.dragArea = Builder.node( 'div', { 'class': cNamePrefix + 'dragArea' }, overlays ); - - this.handleN = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleN' } ); - this.handleNE = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleNE' } ); - this.handleE = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleE' } ); - this.handleSE = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleSE' } ); - this.handleS = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleS' } ); - this.handleSW = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleSW' } ); - this.handleW = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleW' } ); - this.handleNW = Builder.node( 'div', { 'class': cNamePrefix + 'handle ' + cNamePrefix + 'handleNW' } ); - - this.selArea = Builder.node( 'div', { 'class': cNamePrefix + 'selArea' }, - [ - Builder.node( 'div', { 'class': cNamePrefix + 'marqueeHoriz ' + cNamePrefix + 'marqueeNorth' }, [Builder.node( 'span' )] ), - Builder.node( 'div', { 'class': cNamePrefix + 'marqueeVert ' + cNamePrefix + 'marqueeEast' } , [Builder.node( 'span' )] ), - Builder.node( 'div', { 'class': cNamePrefix + 'marqueeHoriz ' + cNamePrefix + 'marqueeSouth' }, [Builder.node( 'span' )] ), - Builder.node( 'div', { 'class': cNamePrefix + 'marqueeVert ' + cNamePrefix + 'marqueeWest' } , [Builder.node( 'span' )] ), - this.handleN, - this.handleNE, - this.handleE, - this.handleSE, - this.handleS, - this.handleSW, - this.handleW, - this.handleNW, - Builder.node( 'div', { 'class': cNamePrefix + 'clickArea' } ) - ] - ); - - this.imgWrap.appendChild( this.img ); - this.imgWrap.appendChild( this.dragArea ); - this.dragArea.appendChild( this.selArea ); - this.dragArea.appendChild( Builder.node( 'div', { 'class': cNamePrefix + 'clickArea' } ) ); - - insertPoint.appendChild( this.imgWrap ); - - // add event observers - this.startDragBind = this.startDrag.bindAsEventListener( this ); - Event.observe( this.dragArea, 'mousedown', this.startDragBind ); - - this.onDragBind = this.onDrag.bindAsEventListener( this ); - Event.observe( document, 'mousemove', this.onDragBind ); - - this.endCropBind = this.endCrop.bindAsEventListener( this ); - Event.observe( document, 'mouseup', this.endCropBind ); - - this.resizeBind = this.startResize.bindAsEventListener( this ); - this.handles = [ this.handleN, this.handleNE, this.handleE, this.handleSE, this.handleS, this.handleSW, this.handleW, this.handleNW ]; - this.registerHandles( true ); - - if( this.options.captureKeys ) { - this.keysBind = this.handleKeys.bindAsEventListener( this ); - Event.observe( document, 'keypress', this.keysBind ); - } - - // attach the dragable to the select area - new CropDraggable( this.selArea, { drawMethod: this.moveArea.bindAsEventListener( this ) } ); - - this.setParams(); - }, - - /** - * Manages adding or removing the handle event handler and hiding or displaying them as appropriate - * - * @access private - * @param boolean registration true = add, false = remove - * @return void - */ - registerHandles: function( registration ) { - for( var i = 0; i < this.handles.length; i++ ) { - var handle = $( this.handles[i] ); - - if( registration ) { - var hideHandle = false; // whether to hide the handle - - // disable handles asappropriate if we've got fixed dimensions - // if both dimensions are fixed we don't need to do much - if( this.fixedWidth && this.fixedHeight ) hideHandle = true; - else if( this.fixedWidth || this.fixedHeight ) { - // if one of the dimensions is fixed then just hide those handles - var isCornerHandle = handle.className.match( /([S|N][E|W])$/ ) - var isWidthHandle = handle.className.match( /(E|W)$/ ); - var isHeightHandle = handle.className.match( /(N|S)$/ ); - if( isCornerHandle ) hideHandle = true; - else if( this.fixedWidth && isWidthHandle ) hideHandle = true; - else if( this.fixedHeight && isHeightHandle ) hideHandle = true; - } - if( hideHandle ) handle.hide(); - else Event.observe( handle, 'mousedown', this.resizeBind ); - } else { - handle.show(); - Event.stopObserving( handle, 'mousedown', this.resizeBind ); - } - } - }, - - /** - * Sets up all the cropper parameters, this can be used to reset the cropper when dynamically - * changing the images - * - * @access private - * @return void - */ - setParams: function() { - /** - * @var int - * The image width - */ - this.imgW = this.img.width; - /** - * @var int - * The image height - */ - this.imgH = this.img.height; - - $( this.north ).setStyle( { height: 0 } ); - $( this.east ).setStyle( { width: 0, height: 0 } ); - $( this.south ).setStyle( { height: 0 } ); - $( this.west ).setStyle( { width: 0, height: 0 } ); - - // resize the container to fit the image - $( this.imgWrap ).setStyle( { 'width': this.imgW + 'px', 'height': this.imgH + 'px' } ); - - // hide the select area - $( this.selArea ).hide(); - - // setup the starting position of the select area - var startCoords = { x1: 0, y1: 0, x2: 0, y2: 0 }; - var validCoordsSet = false; - - // display the select area - if( this.options.onloadCoords != null ) { - // if we've being given some coordinates to - startCoords = this.cloneCoords( this.options.onloadCoords ); - validCoordsSet = true; - } else if( this.options.ratioDim.x > 0 && this.options.ratioDim.y > 0 ) { - // if there is a ratio limit applied and the then set it to initial ratio - startCoords.x1 = Math.ceil( ( this.imgW - this.options.ratioDim.x ) / 2 ); - startCoords.y1 = Math.ceil( ( this.imgH - this.options.ratioDim.y ) / 2 ); - startCoords.x2 = startCoords.x1 + this.options.ratioDim.x; - startCoords.y2 = startCoords.y1 + this.options.ratioDim.y; - validCoordsSet = true; - } - - this.setAreaCoords( startCoords, false, false, 1 ); - - if( this.options.displayOnInit && validCoordsSet ) { - this.selArea.show(); - this.drawArea(); - this.endCrop(); - } - - this.attached = true; - }, - - /** - * Removes the cropper - * - * @access public - * @return void - */ - remove: function() { - if( this.attached ) { - this.attached = false; - - // remove the elements we inserted - this.imgWrap.parentNode.insertBefore( this.img, this.imgWrap ); - this.imgWrap.parentNode.removeChild( this.imgWrap ); - - // remove the event observers - Event.stopObserving( this.dragArea, 'mousedown', this.startDragBind ); - Event.stopObserving( document, 'mousemove', this.onDragBind ); - Event.stopObserving( document, 'mouseup', this.endCropBind ); - this.registerHandles( false ); - if( this.options.captureKeys ) Event.stopObserving( document, 'keypress', this.keysBind ); - } - }, - - /** - * Resets the cropper, can be used either after being removed or any time you wish - * - * @access public - * @return void - */ - reset: function() { - if( !this.attached ) this.onLoad(); - else this.setParams(); - this.endCrop(); - }, - - /** - * Handles the key functionality, currently just using arrow keys to move, if the user - * presses shift then the area will move by 10 pixels - */ - handleKeys: function( e ) { - var dir = { x: 0, y: 0 }; // direction to move it in & the amount in pixels - if( !this.dragging ) { - - // catch the arrow keys - switch( e.keyCode ) { - case( 37 ) : // left - dir.x = -1; - break; - case( 38 ) : // up - dir.y = -1; - break; - case( 39 ) : // right - dir.x = 1; - break - case( 40 ) : // down - dir.y = 1; - break; - } - - if( dir.x != 0 || dir.y != 0 ) { - // if shift is pressed then move by 10 pixels - if( e.shiftKey ) { - dir.x *= 10; - dir.y *= 10; - } - - this.moveArea( [ this.areaCoords.x1 + dir.x, this.areaCoords.y1 + dir.y ] ); - Event.stop( e ); - } - } - }, - - /** - * Calculates the width from the areaCoords - * - * @access private - * @return int - */ - calcW: function() { - return (this.areaCoords.x2 - this.areaCoords.x1) - }, - - /** - * Calculates the height from the areaCoords - * - * @access private - * @return int - */ - calcH: function() { - return (this.areaCoords.y2 - this.areaCoords.y1) - }, - - /** - * Moves the select area to the supplied point (assumes the point is x1 & y1 of the select area) - * - * @access public - * @param array Point for x1 & y1 to move select area to - * @return void - */ - moveArea: function( point ) { - // dump( 'moveArea : ' + point[0] + ',' + point[1] + ',' + ( point[0] + ( this.areaCoords.x2 - this.areaCoords.x1 ) ) + ',' + ( point[1] + ( this.areaCoords.y2 - this.areaCoords.y1 ) ) + '\n' ); - this.setAreaCoords( - { - x1: point[0], - y1: point[1], - x2: point[0] + this.calcW(), - y2: point[1] + this.calcH() - }, - true, - false - ); - this.drawArea(); - }, - - /** - * Clones a co-ordinates object, stops problems with handling them by reference - * - * @access private - * @param obj Coordinate object x1, y1, x2, y2 - * @return obj Coordinate object x1, y1, x2, y2 - */ - cloneCoords: function( coords ) { - return { x1: coords.x1, y1: coords.y1, x2: coords.x2, y2: coords.y2 }; - }, - - /** - * Sets the select coords to those provided but ensures they don't go - * outside the bounding box - * - * @access private - * @param obj Coordinates x1, y1, x2, y2 - * @param boolean Whether this is a move - * @param boolean Whether to apply squaring - * @param obj Direction of mouse along both axis x, y ( -1 = negative, 1 = positive ) only required when moving etc. - * @param string The current resize handle || null - * @return void - */ - setAreaCoords: function( coords, moving, square, direction, resizeHandle ) { - // dump( 'setAreaCoords (in) : ' + coords.x1 + ',' + coords.y1 + ',' + coords.x2 + ',' + coords.y2 ); - if( moving ) { - // if moving - var targW = coords.x2 - coords.x1; - var targH = coords.y2 - coords.y1; - - // ensure we're within the bounds - if( coords.x1 < 0 ) { - coords.x1 = 0; - coords.x2 = targW; - } - if( coords.y1 < 0 ) { - coords.y1 = 0; - coords.y2 = targH; - } - if( coords.x2 > this.imgW ) { - coords.x2 = this.imgW; - coords.x1 = this.imgW - targW; - } - if( coords.y2 > this.imgH ) { - coords.y2 = this.imgH; - coords.y1 = this.imgH - targH; - } - } else { - // ensure we're within the bounds - if( coords.x1 < 0 ) coords.x1 = 0; - if( coords.y1 < 0 ) coords.y1 = 0; - if( coords.x2 > this.imgW ) coords.x2 = this.imgW; - if( coords.y2 > this.imgH ) coords.y2 = this.imgH; - - // This is passed as null in onload - if( direction != null ) { - - // apply the ratio or squaring where appropriate - if( this.ratioX > 0 ) this.applyRatio( coords, { x: this.ratioX, y: this.ratioY }, direction, resizeHandle ); - else if( square ) this.applyRatio( coords, { x: 1, y: 1 }, direction, resizeHandle ); - - var mins = [ this.options.minWidth, this.options.minHeight ]; // minimum dimensions [x,y] - var maxs = [ this.options.maxWidth, this.options.maxHeight ]; // maximum dimensions [x,y] - - // apply dimensions where appropriate - if( mins[0] > 0 || mins[1] > 0 || maxs[0] > 0 || maxs[1] > 0) { - - var coordsTransX = { a1: coords.x1, a2: coords.x2 }; - var coordsTransY = { a1: coords.y1, a2: coords.y2 }; - var boundsX = { min: 0, max: this.imgW }; - var boundsY = { min: 0, max: this.imgH }; - - // handle squaring properly on single axis minimum dimensions - if( (mins[0] != 0 || mins[1] != 0) && square ) { - if( mins[0] > 0 ) mins[1] = mins[0]; - else if( mins[1] > 0 ) mins[0] = mins[1]; - } - - if( (maxs[0] != 0 || maxs[0] != 0) && square ) { - // if we have a max x value & it is less than the max y value then we set the y max to the max x (so we don't go over the minimum maximum of one of the axes - if that makes sense) - if( maxs[0] > 0 && maxs[0] <= maxs[1] ) maxs[1] = maxs[0]; - else if( maxs[1] > 0 && maxs[1] <= maxs[0] ) maxs[0] = maxs[1]; - } - - if( mins[0] > 0 ) this.applyDimRestriction( coordsTransX, mins[0], direction.x, boundsX, 'min' ); - if( mins[1] > 1 ) this.applyDimRestriction( coordsTransY, mins[1], direction.y, boundsY, 'min' ); - - if( maxs[0] > 0 ) this.applyDimRestriction( coordsTransX, maxs[0], direction.x, boundsX, 'max' ); - if( maxs[1] > 1 ) this.applyDimRestriction( coordsTransY, maxs[1], direction.y, boundsY, 'max' ); - - coords = { x1: coordsTransX.a1, y1: coordsTransY.a1, x2: coordsTransX.a2, y2: coordsTransY.a2 }; - } - - } - } - - // dump( 'setAreaCoords (out) : ' + coords.x1 + ',' + coords.y1 + ',' + coords.x2 + ',' + coords.y2 + '\n' ); - this.areaCoords = coords; - }, - - /** - * Applies the supplied dimension restriction to the supplied coordinates along a single axis - * - * @access private - * @param obj Single axis coordinates, a1, a2 (e.g. for the x axis a1 = x1 & a2 = x2) - * @param int The restriction value - * @param int The direction ( -1 = negative, 1 = positive ) - * @param obj The bounds of the image ( for this axis ) - * @param string The dimension restriction type ( 'min' | 'max' ) - * @return void - */ - applyDimRestriction: function( coords, val, direction, bounds, type ) { - var check; - if( type == 'min' ) check = ( ( coords.a2 - coords.a1 ) < val ); - else check = ( ( coords.a2 - coords.a1 ) > val ); - if( check ) { - if( direction == 1 ) coords.a2 = coords.a1 + val; - else coords.a1 = coords.a2 - val; - - // make sure we're still in the bounds (not too pretty for the user, but needed) - if( coords.a1 < bounds.min ) { - coords.a1 = bounds.min; - coords.a2 = val; - } else if( coords.a2 > bounds.max ) { - coords.a1 = bounds.max - val; - coords.a2 = bounds.max; - } - } - }, - - /** - * Applies the supplied ratio to the supplied coordinates - * - * @access private - * @param obj Coordinates, x1, y1, x2, y2 - * @param obj Ratio, x, y - * @param obj Direction of mouse, x & y : -1 == negative 1 == positive - * @param string The current resize handle || null - * @return void - */ - applyRatio : function( coords, ratio, direction, resizeHandle ) { - // dump( 'direction.y : ' + direction.y + '\n'); - var newCoords; - if( resizeHandle == 'N' || resizeHandle == 'S' ) { - // dump( 'north south \n'); - // if moving on either the lone north & south handles apply the ratio on the y axis - newCoords = this.applyRatioToAxis( - { a1: coords.y1, b1: coords.x1, a2: coords.y2, b2: coords.x2 }, - { a: ratio.y, b: ratio.x }, - { a: direction.y, b: direction.x }, - { min: 0, max: this.imgW } - ); - coords.x1 = newCoords.b1; - coords.y1 = newCoords.a1; - coords.x2 = newCoords.b2; - coords.y2 = newCoords.a2; - } else { - // otherwise deal with it as if we're applying the ratio on the x axis - newCoords = this.applyRatioToAxis( - { a1: coords.x1, b1: coords.y1, a2: coords.x2, b2: coords.y2 }, - { a: ratio.x, b: ratio.y }, - { a: direction.x, b: direction.y }, - { min: 0, max: this.imgH } - ); - coords.x1 = newCoords.a1; - coords.y1 = newCoords.b1; - coords.x2 = newCoords.a2; - coords.y2 = newCoords.b2; - } - - }, - - /** - * Applies the provided ratio to the provided coordinates based on provided direction & bounds, - * use to encapsulate functionality to make it easy to apply to either axis. This is probably - * quite hard to visualise so see the x axis example within applyRatio() - * - * Example in parameter details & comments is for requesting applying ratio to x axis. - * - * @access private - * @param obj Coords object (a1, b1, a2, b2) where a = x & b = y in example - * @param obj Ratio object (a, b) where a = x & b = y in example - * @param obj Direction object (a, b) where a = x & b = y in example - * @param obj Bounds (min, max) - * @return obj Coords object (a1, b1, a2, b2) where a = x & b = y in example - */ - applyRatioToAxis: function( coords, ratio, direction, bounds ) { - var newCoords = Object.extend( coords, {} ); - var calcDimA = newCoords.a2 - newCoords.a1; // calculate dimension a (e.g. width) - var targDimB = Math.floor( calcDimA * ratio.b / ratio.a ); // the target dimension b (e.g. height) - var targB; // to hold target b (e.g. y value) - var targDimA; // to hold target dimension a (e.g. width) - var calcDimB = null; // to hold calculated dimension b (e.g. height) - - // dump( 'newCoords[0]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n'); - - if( direction.b == 1 ) { // if travelling in a positive direction - // make sure we're not going out of bounds - targB = newCoords.b1 + targDimB; - if( targB > bounds.max ) { - targB = bounds.max; - calcDimB = targB - newCoords.b1; // calcuate dimension b (e.g. height) - } - - newCoords.b2 = targB; - } else { // if travelling in a negative direction - // make sure we're not going out of bounds - targB = newCoords.b2 - targDimB; - if( targB < bounds.min ) { - targB = bounds.min; - calcDimB = targB + newCoords.b2; // calcuate dimension b (e.g. height) - } - newCoords.b1 = targB; - } - - // dump( 'newCoords[1]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n'); - - // apply the calculated dimensions - if( calcDimB != null ) { - targDimA = Math.floor( calcDimB * ratio.a / ratio.b ); - - if( direction.a == 1 ) newCoords.a2 = newCoords.a1 + targDimA; - else newCoords.a1 = newCoords.a1 = newCoords.a2 - targDimA; - } - - // dump( 'newCoords[2]: ' + newCoords.a1 + ',' + newCoords.b1 + ','+ newCoords.a2 + ',' + newCoords.b2 + '\n'); - - return newCoords; - }, - - /** - * Draws the select area - * - * @access private - * @return void - */ - drawArea: function( ) { - /* - * NOTE: I'm not using the Element.setStyle() shortcut as they make it - * quite sluggish on Mac based browsers - */ - // dump( 'drawArea : ' + this.areaCoords.x1 + ',' + this.areaCoords.y1 + ',' + this.areaCoords.x2 + ',' + this.areaCoords.y2 + '\n' ); - var areaWidth = this.calcW(); - var areaHeight = this.calcH(); - - /* - * Calculate all the style strings before we use them, allows reuse & produces quicker - * rendering (especially noticable in Mac based browsers) - */ - var px = 'px'; - var params = [ - this.areaCoords.x1 + px, // the left of the selArea - this.areaCoords.y1 + px, // the top of the selArea - areaWidth + px, // width of the selArea - areaHeight + px, // height of the selArea - this.areaCoords.x2 + px, // bottom of the selArea - this.areaCoords.y2 + px, // right of the selArea - (this.img.width - this.areaCoords.x2) + px, // right edge of selArea - (this.img.height - this.areaCoords.y2) + px // bottom edge of selArea - ]; - - // do the select area - var areaStyle = this.selArea.style; - areaStyle.left = params[0]; - areaStyle.top = params[1]; - areaStyle.width = params[2]; - areaStyle.height = params[3]; - - // position the north, east, south & west handles - var horizHandlePos = Math.ceil( (areaWidth - 6) / 2 ) + px; - var vertHandlePos = Math.ceil( (areaHeight - 6) / 2 ) + px; - - this.handleN.style.left = horizHandlePos; - this.handleE.style.top = vertHandlePos; - this.handleS.style.left = horizHandlePos; - this.handleW.style.top = vertHandlePos; - - // draw the four overlays - this.north.style.height = params[1]; - - var eastStyle = this.east.style; - eastStyle.top = params[1]; - eastStyle.height = params[3]; - eastStyle.left = params[4]; - eastStyle.width = params[6]; - - var southStyle = this.south.style; - southStyle.top = params[5]; - southStyle.height = params[7]; - - var westStyle = this.west.style; - westStyle.top = params[1]; - westStyle.height = params[3]; - westStyle.width = params[0]; - - // call the draw method on sub classes - this.subDrawArea(); - - this.forceReRender(); - }, - - /** - * Force the re-rendering of the selArea element which fixes rendering issues in Safari - * & IE PC, especially evident when re-sizing perfectly vertical using any of the south handles - * - * @access private - * @return void - */ - forceReRender: function() { - if( this.isIE || this.isWebKit) { - var n = document.createTextNode(' '); - var d,el,fixEL,i; - - if( this.isIE ) fixEl = this.selArea; - else if( this.isWebKit ) { - fixEl = document.getElementsByClassName( 'imgCrop_marqueeSouth', this.imgWrap )[0]; - /* we have to be a bit more forceful for Safari, otherwise the the marquee & - * the south handles still don't move - */ - d = Builder.node( 'div', '' ); - d.style.visibility = 'hidden'; - - var classList = ['SE','S','SW']; - for( i = 0; i < classList.length; i++ ) { - el = document.getElementsByClassName( 'imgCrop_handle' + classList[i], this.selArea )[0]; - if( el.childNodes.length ) el.removeChild( el.childNodes[0] ); - el.appendChild(d); - } - } - fixEl.appendChild(n); - fixEl.removeChild(n); - } - }, - - /** - * Starts the resize - * - * @access private - * @param obj Event - * @return void - */ - startResize: function( e ) { - this.startCoords = this.cloneCoords( this.areaCoords ); - - this.resizing = true; - this.resizeHandle = Event.element( e ).classNames().toString().replace(/([^N|NE|E|SE|S|SW|W|NW])+/, ''); - // dump( 'this.resizeHandle : ' + this.resizeHandle + '\n' ); - Event.stop( e ); - }, - - /** - * Starts the drag - * - * @access private - * @param obj Event - * @return void - */ - startDrag: function( e ) { - this.selArea.show(); - this.clickCoords = this.getCurPos( e ); - - this.setAreaCoords( { x1: this.clickCoords.x, y1: this.clickCoords.y, x2: this.clickCoords.x, y2: this.clickCoords.y }, false, false, null ); - - this.dragging = true; - this.onDrag( e ); // incase the user just clicks once after already making a selection - Event.stop( e ); - }, - - /** - * Gets the current cursor position relative to the image - * - * @access private - * @param obj Event - * @return obj x,y pixels of the cursor - */ - getCurPos: function( e ) { - // get the offsets for the wrapper within the document - var el = this.imgWrap, wrapOffsets = Position.cumulativeOffset( el ); - // remove any scrolling that is applied to the wrapper (this may be buggy) - don't count the scroll on the body as that won't affect us - while( el.nodeName != 'BODY' ) { - wrapOffsets[1] -= el.scrollTop || 0; - wrapOffsets[0] -= el.scrollLeft || 0; - el = el.parentNode; - } - return curPos = { - x: Event.pointerX(e) - wrapOffsets[0], - y: Event.pointerY(e) - wrapOffsets[1] - } - }, - - /** - * Performs the drag for both resize & inital draw dragging - * - * @access private - * @param obj Event - * @return void - */ - onDrag: function( e ) { - if( this.dragging || this.resizing ) { - - var resizeHandle = null; - var curPos = this.getCurPos( e ); - var newCoords = this.cloneCoords( this.areaCoords ); - var direction = { x: 1, y: 1 }; - - if( this.dragging ) { - if( curPos.x < this.clickCoords.x ) direction.x = -1; - if( curPos.y < this.clickCoords.y ) direction.y = -1; - - this.transformCoords( curPos.x, this.clickCoords.x, newCoords, 'x' ); - this.transformCoords( curPos.y, this.clickCoords.y, newCoords, 'y' ); - } else if( this.resizing ) { - resizeHandle = this.resizeHandle; - // do x movements first - if( resizeHandle.match(/E/) ) { - // if we're moving an east handle - this.transformCoords( curPos.x, this.startCoords.x1, newCoords, 'x' ); - if( curPos.x < this.startCoords.x1 ) direction.x = -1; - } else if( resizeHandle.match(/W/) ) { - // if we're moving an west handle - this.transformCoords( curPos.x, this.startCoords.x2, newCoords, 'x' ); - if( curPos.x < this.startCoords.x2 ) direction.x = -1; - } - - // do y movements second - if( resizeHandle.match(/N/) ) { - // if we're moving an north handle - this.transformCoords( curPos.y, this.startCoords.y2, newCoords, 'y' ); - if( curPos.y < this.startCoords.y2 ) direction.y = -1; - } else if( resizeHandle.match(/S/) ) { - // if we're moving an south handle - this.transformCoords( curPos.y, this.startCoords.y1, newCoords, 'y' ); - if( curPos.y < this.startCoords.y1 ) direction.y = -1; - } - - } - - this.setAreaCoords( newCoords, false, e.shiftKey, direction, resizeHandle ); - this.drawArea(); - Event.stop( e ); // stop the default event (selecting images & text) in Safari & IE PC - } - }, - - /** - * Applies the appropriate transform to supplied co-ordinates, on the - * defined axis, depending on the relationship of the supplied values - * - * @access private - * @param int Current value of pointer - * @param int Base value to compare current pointer val to - * @param obj Coordinates to apply transformation on x1, x2, y1, y2 - * @param string Axis to apply transformation on 'x' || 'y' - * @return void - */ - transformCoords : function( curVal, baseVal, coords, axis ) { - var newVals = [ curVal, baseVal ]; - if( curVal > baseVal ) newVals.reverse(); - coords[ axis + '1' ] = newVals[0]; - coords[ axis + '2' ] = newVals[1]; - }, - - /** - * Ends the crop & passes the values of the select area on to the appropriate - * callback function on completion of a crop - * - * @access private - * @return void - */ - endCrop : function() { - this.dragging = false; - this.resizing = false; - - this.options.onEndCrop( - this.areaCoords, - { - width: this.calcW(), - height: this.calcH() - } - ); - }, - - /** - * Abstract method called on the end of initialization - * - * @access private - * @abstract - * @return void - */ - subInitialize: function() {}, - - /** - * Abstract method called on the end of drawArea() - * - * @access private - * @abstract - * @return void - */ - subDrawArea: function() {} -}; - - - - -/** - * Extend the Cropper.Img class to allow for presentation of a preview image of the resulting crop, - * the option for displayOnInit is always overridden to true when displaying a preview image - * - * Usage: - * @param obj Image element to attach to - * @param obj Optional options: - * - see Cropper.Img for base options - * - * - previewWrap obj - * HTML element that will be used as a container for the preview image - */ -Cropper.ImgWithPreview = Class.create(); - -Object.extend( Object.extend( Cropper.ImgWithPreview.prototype, Cropper.Img.prototype ), { - - /** - * Implements the abstract method from Cropper.Img to initialize preview image settings. - * Will only attach a preview image is the previewWrap element is defined and the minWidth - * & minHeight options are set. - * - * @see Croper.Img.subInitialize - */ - subInitialize: function() { - /** - * Whether or not we've attached a preview image - * @var boolean - */ - this.hasPreviewImg = false; - if( typeof(this.options.previewWrap) != 'undefined' - && this.options.minWidth > 0 - && this.options.minHeight > 0 - ) { - /** - * The preview image wrapper element - * @var obj HTML element - */ - this.previewWrap = $( this.options.previewWrap ); - /** - * The preview image element - * @var obj HTML IMG element - */ - this.previewImg = this.img.cloneNode( false ); - // set the ID of the preview image to be unique - this.previewImg.id = 'imgCrop_' + this.previewImg.id; - - - // set the displayOnInit option to true so we display the select area at the same time as the thumbnail - this.options.displayOnInit = true; - - this.hasPreviewImg = true; - - this.previewWrap.addClassName( 'imgCrop_previewWrap' ); - - this.previewWrap.setStyle( - { - width: this.options.minWidth + 'px', - height: this.options.minHeight + 'px' - } - ); - - this.previewWrap.appendChild( this.previewImg ); - } - }, - - /** - * Implements the abstract method from Cropper.Img to draw the preview image - * - * @see Croper.Img.subDrawArea - */ - subDrawArea: function() { - if( this.hasPreviewImg ) { - // get the ratio of the select area to the src image - var calcWidth = this.calcW(); - var calcHeight = this.calcH(); - // ratios for the dimensions of the preview image - var dimRatio = { - x: this.imgW / calcWidth, - y: this.imgH / calcHeight - }; - //ratios for the positions within the preview - var posRatio = { - x: calcWidth / this.options.minWidth, - y: calcHeight / this.options.minHeight - }; - - // setting the positions in an obj before apply styles for rendering speed increase - var calcPos = { - w: Math.ceil( this.options.minWidth * dimRatio.x ) + 'px', - h: Math.ceil( this.options.minHeight * dimRatio.y ) + 'px', - x: '-' + Math.ceil( this.areaCoords.x1 / posRatio.x ) + 'px', - y: '-' + Math.ceil( this.areaCoords.y1 / posRatio.y ) + 'px' - } - - var previewStyle = this.previewImg.style; - previewStyle.width = calcPos.w; - previewStyle.height = calcPos.h; - previewStyle.left = calcPos.x; - previewStyle.top = calcPos.y; - } - } - -}); diff --git a/library/cropper/lib/builder.js b/library/cropper/lib/builder.js deleted file mode 100644 index 5b15ba939..000000000 --- a/library/cropper/lib/builder.js +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// -// See scriptaculous.js for full license. - -var Builder = { - NODEMAP: { - AREA: 'map', - CAPTION: 'table', - COL: 'table', - COLGROUP: 'table', - LEGEND: 'fieldset', - OPTGROUP: 'select', - OPTION: 'select', - PARAM: 'object', - TBODY: 'table', - TD: 'table', - TFOOT: 'table', - TH: 'table', - THEAD: 'table', - TR: 'table' - }, - // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, - // due to a Firefox bug - node: function(elementName) { - elementName = elementName.toUpperCase(); - - // try innerHTML approach - var parentTag = this.NODEMAP[elementName] || 'div'; - var parentElement = document.createElement(parentTag); - try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 - parentElement.innerHTML = "<" + elementName + ">"; - } catch(e) {} - var element = parentElement.firstChild || null; - - // see if browser added wrapping tags - if(element && (element.tagName != elementName)) - element = element.getElementsByTagName(elementName)[0]; - - // fallback to createElement approach - if(!element) element = document.createElement(elementName); - - // abort if nothing could be created - if(!element) return; - - // attributes (or text) - if(arguments[1]) - if(this._isStringOrNumber(arguments[1]) || - (arguments[1] instanceof Array)) { - this._children(element, arguments[1]); - } else { - var attrs = this._attributes(arguments[1]); - if(attrs.length) { - try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 - parentElement.innerHTML = "<" +elementName + " " + - attrs + ">"; - } catch(e) {} - element = parentElement.firstChild || null; - // workaround firefox 1.0.X bug - if(!element) { - element = document.createElement(elementName); - for(attr in arguments[1]) - element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; - } - if(element.tagName != elementName) - element = parentElement.getElementsByTagName(elementName)[0]; - } - } - - // text, or array of children - if(arguments[2]) - this._children(element, arguments[2]); - - return element; - }, - _text: function(text) { - return document.createTextNode(text); - }, - _attributes: function(attributes) { - var attrs = []; - for(attribute in attributes) - attrs.push((attribute=='className' ? 'class' : attribute) + - '="' + attributes[attribute].toString().escapeHTML() + '"'); - return attrs.join(" "); - }, - _children: function(element, children) { - if(typeof children=='object') { // array can hold nodes and text - children.flatten().each( function(e) { - if(typeof e=='object') - element.appendChild(e) - else - if(Builder._isStringOrNumber(e)) - element.appendChild(Builder._text(e)); - }); - } else - if(Builder._isStringOrNumber(children)) - element.appendChild(Builder._text(children)); - }, - _isStringOrNumber: function(param) { - return(typeof param=='string' || typeof param=='number'); - } -} \ No newline at end of file diff --git a/library/cropper/lib/controls.js b/library/cropper/lib/controls.js deleted file mode 100644 index de0261ed5..000000000 --- a/library/cropper/lib/controls.js +++ /dev/null @@ -1,815 +0,0 @@ -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan) -// (c) 2005 Jon Tirsen (http://www.tirsen.com) -// Contributors: -// Richard Livsey -// Rahul Bhargava -// Rob Wills -// -// See scriptaculous.js for full license. - -// Autocompleter.Base handles all the autocompletion functionality -// that's independent of the data source for autocompletion. This -// includes drawing the autocompletion menu, observing keyboard -// and mouse events, and similar. -// -// Specific autocompleters need to provide, at the very least, -// a getUpdatedChoices function that will be invoked every time -// the text inside the monitored textbox changes. This method -// should get the text for which to provide autocompletion by -// invoking this.getToken(), NOT by directly accessing -// this.element.value. This is to allow incremental tokenized -// autocompletion. Specific auto-completion logic (AJAX, etc) -// belongs in getUpdatedChoices. -// -// Tokenized incremental autocompletion is enabled automatically -// when an autocompleter is instantiated with the 'tokens' option -// in the options parameter, e.g.: -// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); -// will incrementally autocomplete with a comma as the token. -// Additionally, ',' in the above example can be replaced with -// a token array, e.g. { tokens: [',', '\n'] } which -// enables autocompletion on multiple tokens. This is most -// useful when one of the tokens is \n (a newline), as it -// allows smart autocompletion after linebreaks. - -var Autocompleter = {} -Autocompleter.Base = function() {}; -Autocompleter.Base.prototype = { - baseInitialize: function(element, update, options) { - this.element = $(element); - this.update = $(update); - this.hasFocus = false; - this.changed = false; - this.active = false; - this.index = 0; - this.entryCount = 0; - - if (this.setOptions) - this.setOptions(options); - else - this.options = options || {}; - - this.options.paramName = this.options.paramName || this.element.name; - this.options.tokens = this.options.tokens || []; - this.options.frequency = this.options.frequency || 0.4; - this.options.minChars = this.options.minChars || 1; - this.options.onShow = this.options.onShow || - function(element, update){ - if(!update.style.position || update.style.position=='absolute') { - update.style.position = 'absolute'; - Position.clone(element, update, {setHeight: false, offsetTop: element.offsetHeight}); - } - Effect.Appear(update,{duration:0.15}); - }; - this.options.onHide = this.options.onHide || - function(element, update){ new Effect.Fade(update,{duration:0.15}) }; - - if (typeof(this.options.tokens) == 'string') - this.options.tokens = new Array(this.options.tokens); - - this.observer = null; - - this.element.setAttribute('autocomplete','off'); - - Element.hide(this.update); - - Event.observe(this.element, "blur", this.onBlur.bindAsEventListener(this)); - Event.observe(this.element, "keypress", this.onKeyPress.bindAsEventListener(this)); - }, - - show: function() { - if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); - if(!this.iefix && - (navigator.appVersion.indexOf('MSIE')>0) && - (navigator.userAgent.indexOf('Opera')<0) && - (Element.getStyle(this.update, 'position')=='absolute')) { - new Insertion.After(this.update, - ''); - this.iefix = $(this.update.id+'_iefix'); - } - if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); - }, - - fixIEOverlapping: function() { - Position.clone(this.update, this.iefix); - this.iefix.style.zIndex = 1; - this.update.style.zIndex = 2; - Element.show(this.iefix); - }, - - hide: function() { - this.stopIndicator(); - if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); - if(this.iefix) Element.hide(this.iefix); - }, - - startIndicator: function() { - if(this.options.indicator) Element.show(this.options.indicator); - }, - - stopIndicator: function() { - if(this.options.indicator) Element.hide(this.options.indicator); - }, - - onKeyPress: function(event) { - if(this.active) - switch(event.keyCode) { - case Event.KEY_TAB: - case Event.KEY_RETURN: - this.selectEntry(); - Event.stop(event); - case Event.KEY_ESC: - this.hide(); - this.active = false; - Event.stop(event); - return; - case Event.KEY_LEFT: - case Event.KEY_RIGHT: - return; - case Event.KEY_UP: - this.markPrevious(); - this.render(); - if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); - return; - case Event.KEY_DOWN: - this.markNext(); - this.render(); - if(navigator.appVersion.indexOf('AppleWebKit')>0) Event.stop(event); - return; - } - else - if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || - (navigator.appVersion.indexOf('AppleWebKit') > 0 && event.keyCode == 0)) return; - - this.changed = true; - this.hasFocus = true; - - if(this.observer) clearTimeout(this.observer); - this.observer = - setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); - }, - - activate: function() { - this.changed = false; - this.hasFocus = true; - this.getUpdatedChoices(); - }, - - onHover: function(event) { - var element = Event.findElement(event, 'LI'); - if(this.index != element.autocompleteIndex) - { - this.index = element.autocompleteIndex; - this.render(); - } - Event.stop(event); - }, - - onClick: function(event) { - var element = Event.findElement(event, 'LI'); - this.index = element.autocompleteIndex; - this.selectEntry(); - this.hide(); - }, - - onBlur: function(event) { - // needed to make click events working - setTimeout(this.hide.bind(this), 250); - this.hasFocus = false; - this.active = false; - }, - - render: function() { - if(this.entryCount > 0) { - for (var i = 0; i < this.entryCount; i++) - this.index==i ? - Element.addClassName(this.getEntry(i),"selected") : - Element.removeClassName(this.getEntry(i),"selected"); - - if(this.hasFocus) { - this.show(); - this.active = true; - } - } else { - this.active = false; - this.hide(); - } - }, - - markPrevious: function() { - if(this.index > 0) this.index-- - else this.index = this.entryCount-1; - }, - - markNext: function() { - if(this.index < this.entryCount-1) this.index++ - else this.index = 0; - }, - - getEntry: function(index) { - return this.update.firstChild.childNodes[index]; - }, - - getCurrentEntry: function() { - return this.getEntry(this.index); - }, - - selectEntry: function() { - this.active = false; - this.updateElement(this.getCurrentEntry()); - }, - - updateElement: function(selectedElement) { - if (this.options.updateElement) { - this.options.updateElement(selectedElement); - return; - } - var value = ''; - if (this.options.select) { - var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; - if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); - } else - value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); - - var lastTokenPos = this.findLastToken(); - if (lastTokenPos != -1) { - var newValue = this.element.value.substr(0, lastTokenPos + 1); - var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); - if (whitespace) - newValue += whitespace[0]; - this.element.value = newValue + value; - } else { - this.element.value = value; - } - this.element.focus(); - - if (this.options.afterUpdateElement) - this.options.afterUpdateElement(this.element, selectedElement); - }, - - updateChoices: function(choices) { - if(!this.changed && this.hasFocus) { - this.update.innerHTML = choices; - Element.cleanWhitespace(this.update); - Element.cleanWhitespace(this.update.firstChild); - - if(this.update.firstChild && this.update.firstChild.childNodes) { - this.entryCount = - this.update.firstChild.childNodes.length; - for (var i = 0; i < this.entryCount; i++) { - var entry = this.getEntry(i); - entry.autocompleteIndex = i; - this.addObservers(entry); - } - } else { - this.entryCount = 0; - } - - this.stopIndicator(); - - this.index = 0; - this.render(); - } - }, - - addObservers: function(element) { - Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); - Event.observe(element, "click", this.onClick.bindAsEventListener(this)); - }, - - onObserverEvent: function() { - this.changed = false; - if(this.getToken().length>=this.options.minChars) { - this.startIndicator(); - this.getUpdatedChoices(); - } else { - this.active = false; - this.hide(); - } - }, - - getToken: function() { - var tokenPos = this.findLastToken(); - if (tokenPos != -1) - var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); - else - var ret = this.element.value; - - return /\n/.test(ret) ? '' : ret; - }, - - findLastToken: function() { - var lastTokenPos = -1; - - for (var i=0; i lastTokenPos) - lastTokenPos = thisTokenPos; - } - return lastTokenPos; - } -} - -Ajax.Autocompleter = Class.create(); -Object.extend(Object.extend(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype), { - initialize: function(element, update, url, options) { - this.baseInitialize(element, update, options); - this.options.asynchronous = true; - this.options.onComplete = this.onComplete.bind(this); - this.options.defaultParams = this.options.parameters || null; - this.url = url; - }, - - getUpdatedChoices: function() { - entry = encodeURIComponent(this.options.paramName) + '=' + - encodeURIComponent(this.getToken()); - - this.options.parameters = this.options.callback ? - this.options.callback(this.element, entry) : entry; - - if(this.options.defaultParams) - this.options.parameters += '&' + this.options.defaultParams; - - new Ajax.Request(this.url, this.options); - }, - - onComplete: function(request) { - this.updateChoices(request.responseText); - } - -}); - -// The local array autocompleter. Used when you'd prefer to -// inject an array of autocompletion options into the page, rather -// than sending out Ajax queries, which can be quite slow sometimes. -// -// The constructor takes four parameters. The first two are, as usual, -// the id of the monitored textbox, and id of the autocompletion menu. -// The third is the array you want to autocomplete from, and the fourth -// is the options block. -// -// Extra local autocompletion options: -// - choices - How many autocompletion choices to offer -// -// - partialSearch - If false, the autocompleter will match entered -// text only at the beginning of strings in the -// autocomplete array. Defaults to true, which will -// match text at the beginning of any *word* in the -// strings in the autocomplete array. If you want to -// search anywhere in the string, additionally set -// the option fullSearch to true (default: off). -// -// - fullSsearch - Search anywhere in autocomplete array strings. -// -// - partialChars - How many characters to enter before triggering -// a partial match (unlike minChars, which defines -// how many characters are required to do any match -// at all). Defaults to 2. -// -// - ignoreCase - Whether to ignore case when autocompleting. -// Defaults to true. -// -// It's possible to pass in a custom function as the 'selector' -// option, if you prefer to write your own autocompletion logic. -// In that case, the other options above will not apply unless -// you support them. - -Autocompleter.Local = Class.create(); -Autocompleter.Local.prototype = Object.extend(new Autocompleter.Base(), { - initialize: function(element, update, array, options) { - this.baseInitialize(element, update, options); - this.options.array = array; - }, - - getUpdatedChoices: function() { - this.updateChoices(this.options.selector(this)); - }, - - setOptions: function(options) { - this.options = Object.extend({ - choices: 10, - partialSearch: true, - partialChars: 2, - ignoreCase: true, - fullSearch: false, - selector: function(instance) { - var ret = []; // Beginning matches - var partial = []; // Inside matches - var entry = instance.getToken(); - var count = 0; - - for (var i = 0; i < instance.options.array.length && - ret.length < instance.options.choices ; i++) { - - var elem = instance.options.array[i]; - var foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase()) : - elem.indexOf(entry); - - while (foundPos != -1) { - if (foundPos == 0 && elem.length != entry.length) { - ret.push("
  • " + elem.substr(0, entry.length) + "" + - elem.substr(entry.length) + "
  • "); - break; - } else if (entry.length >= instance.options.partialChars && - instance.options.partialSearch && foundPos != -1) { - if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { - partial.push("
  • " + elem.substr(0, foundPos) + "" + - elem.substr(foundPos, entry.length) + "" + elem.substr( - foundPos + entry.length) + "
  • "); - break; - } - } - - foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : - elem.indexOf(entry, foundPos + 1); - - } - } - if (partial.length) - ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) - return "
      " + ret.join('') + "
    "; - } - }, options || {}); - } -}); - -// AJAX in-place editor -// -// see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor - -// Use this if you notice weird scrolling problems on some browsers, -// the DOM might be a bit confused when this gets called so do this -// waits 1 ms (with setTimeout) until it does the activation -Field.scrollFreeActivate = function(field) { - setTimeout(function() { - Field.activate(field); - }, 1); -} - -Ajax.InPlaceEditor = Class.create(); -Ajax.InPlaceEditor.defaultHighlightColor = "#FFFF99"; -Ajax.InPlaceEditor.prototype = { - initialize: function(element, url, options) { - this.url = url; - this.element = $(element); - - this.options = Object.extend({ - okButton: true, - okText: "ok", - cancelLink: true, - cancelText: "cancel", - savingText: "Saving...", - clickToEditText: "Click to edit", - okText: "ok", - rows: 1, - onComplete: function(transport, element) { - new Effect.Highlight(element, {startcolor: this.options.highlightcolor}); - }, - onFailure: function(transport) { - alert("Error communicating with the server: " + transport.responseText.stripTags()); - }, - callback: function(form) { - return Form.serialize(form); - }, - handleLineBreaks: true, - loadingText: 'Loading...', - savingClassName: 'inplaceeditor-saving', - loadingClassName: 'inplaceeditor-loading', - formClassName: 'inplaceeditor-form', - highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, - highlightendcolor: "#FFFFFF", - externalControl: null, - submitOnBlur: false, - ajaxOptions: {}, - evalScripts: false - }, options || {}); - - if(!this.options.formId && this.element.id) { - this.options.formId = this.element.id + "-inplaceeditor"; - if ($(this.options.formId)) { - // there's already a form with that name, don't specify an id - this.options.formId = null; - } - } - - if (this.options.externalControl) { - this.options.externalControl = $(this.options.externalControl); - } - - this.originalBackground = Element.getStyle(this.element, 'background-color'); - if (!this.originalBackground) { - this.originalBackground = "transparent"; - } - - this.element.title = this.options.clickToEditText; - - this.onclickListener = this.enterEditMode.bindAsEventListener(this); - this.mouseoverListener = this.enterHover.bindAsEventListener(this); - this.mouseoutListener = this.leaveHover.bindAsEventListener(this); - Event.observe(this.element, 'click', this.onclickListener); - Event.observe(this.element, 'mouseover', this.mouseoverListener); - Event.observe(this.element, 'mouseout', this.mouseoutListener); - if (this.options.externalControl) { - Event.observe(this.options.externalControl, 'click', this.onclickListener); - Event.observe(this.options.externalControl, 'mouseover', this.mouseoverListener); - Event.observe(this.options.externalControl, 'mouseout', this.mouseoutListener); - } - }, - enterEditMode: function(evt) { - if (this.saving) return; - if (this.editing) return; - this.editing = true; - this.onEnterEditMode(); - if (this.options.externalControl) { - Element.hide(this.options.externalControl); - } - Element.hide(this.element); - this.createForm(); - this.element.parentNode.insertBefore(this.form, this.element); - Field.scrollFreeActivate(this.editField); - // stop the event to avoid a page refresh in Safari - if (evt) { - Event.stop(evt); - } - return false; - }, - createForm: function() { - this.form = document.createElement("form"); - this.form.id = this.options.formId; - Element.addClassName(this.form, this.options.formClassName) - this.form.onsubmit = this.onSubmit.bind(this); - - this.createEditField(); - - if (this.options.textarea) { - var br = document.createElement("br"); - this.form.appendChild(br); - } - - if (this.options.okButton) { - okButton = document.createElement("input"); - okButton.type = "submit"; - okButton.value = this.options.okText; - okButton.className = 'editor_ok_button'; - this.form.appendChild(okButton); - } - - if (this.options.cancelLink) { - cancelLink = document.createElement("a"); - cancelLink.href = "#"; - cancelLink.appendChild(document.createTextNode(this.options.cancelText)); - cancelLink.onclick = this.onclickCancel.bind(this); - cancelLink.className = 'editor_cancel'; - this.form.appendChild(cancelLink); - } - }, - hasHTMLLineBreaks: function(string) { - if (!this.options.handleLineBreaks) return false; - return string.match(/
    /i); - }, - convertHTMLLineBreaks: function(string) { - return string.replace(/
    /gi, "\n").replace(//gi, "\n").replace(/<\/p>/gi, "\n").replace(/

    /gi, ""); - }, - createEditField: function() { - var text; - if(this.options.loadTextURL) { - text = this.options.loadingText; - } else { - text = this.getText(); - } - - var obj = this; - - if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { - this.options.textarea = false; - var textField = document.createElement("input"); - textField.obj = this; - textField.type = "text"; - textField.name = "value"; - textField.value = text; - textField.style.backgroundColor = this.options.highlightcolor; - textField.className = 'editor_field'; - var size = this.options.size || this.options.cols || 0; - if (size != 0) textField.size = size; - if (this.options.submitOnBlur) - textField.onblur = this.onSubmit.bind(this); - this.editField = textField; - } else { - this.options.textarea = true; - var textArea = document.createElement("textarea"); - textArea.obj = this; - textArea.name = "value"; - textArea.value = this.convertHTMLLineBreaks(text); - textArea.rows = this.options.rows; - textArea.cols = this.options.cols || 40; - textArea.className = 'editor_field'; - if (this.options.submitOnBlur) - textArea.onblur = this.onSubmit.bind(this); - this.editField = textArea; - } - - if(this.options.loadTextURL) { - this.loadExternalText(); - } - this.form.appendChild(this.editField); - }, - getText: function() { - return this.element.innerHTML; - }, - loadExternalText: function() { - Element.addClassName(this.form, this.options.loadingClassName); - this.editField.disabled = true; - new Ajax.Request( - this.options.loadTextURL, - Object.extend({ - asynchronous: true, - onComplete: this.onLoadedExternalText.bind(this) - }, this.options.ajaxOptions) - ); - }, - onLoadedExternalText: function(transport) { - Element.removeClassName(this.form, this.options.loadingClassName); - this.editField.disabled = false; - this.editField.value = transport.responseText.stripTags(); - }, - onclickCancel: function() { - this.onComplete(); - this.leaveEditMode(); - return false; - }, - onFailure: function(transport) { - this.options.onFailure(transport); - if (this.oldInnerHTML) { - this.element.innerHTML = this.oldInnerHTML; - this.oldInnerHTML = null; - } - return false; - }, - onSubmit: function() { - // onLoading resets these so we need to save them away for the Ajax call - var form = this.form; - var value = this.editField.value; - - // do this first, sometimes the ajax call returns before we get a chance to switch on Saving... - // which means this will actually switch on Saving... *after* we've left edit mode causing Saving... - // to be displayed indefinitely - this.onLoading(); - - if (this.options.evalScripts) { - new Ajax.Request( - this.url, Object.extend({ - parameters: this.options.callback(form, value), - onComplete: this.onComplete.bind(this), - onFailure: this.onFailure.bind(this), - asynchronous:true, - evalScripts:true - }, this.options.ajaxOptions)); - } else { - new Ajax.Updater( - { success: this.element, - // don't update on failure (this could be an option) - failure: null }, - this.url, Object.extend({ - parameters: this.options.callback(form, value), - onComplete: this.onComplete.bind(this), - onFailure: this.onFailure.bind(this) - }, this.options.ajaxOptions)); - } - // stop the event to avoid a page refresh in Safari - if (arguments.length > 1) { - Event.stop(arguments[0]); - } - return false; - }, - onLoading: function() { - this.saving = true; - this.removeForm(); - this.leaveHover(); - this.showSaving(); - }, - showSaving: function() { - this.oldInnerHTML = this.element.innerHTML; - this.element.innerHTML = this.options.savingText; - Element.addClassName(this.element, this.options.savingClassName); - this.element.style.backgroundColor = this.originalBackground; - Element.show(this.element); - }, - removeForm: function() { - if(this.form) { - if (this.form.parentNode) Element.remove(this.form); - this.form = null; - } - }, - enterHover: function() { - if (this.saving) return; - this.element.style.backgroundColor = this.options.highlightcolor; - if (this.effect) { - this.effect.cancel(); - } - Element.addClassName(this.element, this.options.hoverClassName) - }, - leaveHover: function() { - if (this.options.backgroundColor) { - this.element.style.backgroundColor = this.oldBackground; - } - Element.removeClassName(this.element, this.options.hoverClassName) - if (this.saving) return; - this.effect = new Effect.Highlight(this.element, { - startcolor: this.options.highlightcolor, - endcolor: this.options.highlightendcolor, - restorecolor: this.originalBackground - }); - }, - leaveEditMode: function() { - Element.removeClassName(this.element, this.options.savingClassName); - this.removeForm(); - this.leaveHover(); - this.element.style.backgroundColor = this.originalBackground; - Element.show(this.element); - if (this.options.externalControl) { - Element.show(this.options.externalControl); - } - this.editing = false; - this.saving = false; - this.oldInnerHTML = null; - this.onLeaveEditMode(); - }, - onComplete: function(transport) { - this.leaveEditMode(); - this.options.onComplete.bind(this)(transport, this.element); - }, - onEnterEditMode: function() {}, - onLeaveEditMode: function() {}, - dispose: function() { - if (this.oldInnerHTML) { - this.element.innerHTML = this.oldInnerHTML; - } - this.leaveEditMode(); - Event.stopObserving(this.element, 'click', this.onclickListener); - Event.stopObserving(this.element, 'mouseover', this.mouseoverListener); - Event.stopObserving(this.element, 'mouseout', this.mouseoutListener); - if (this.options.externalControl) { - Event.stopObserving(this.options.externalControl, 'click', this.onclickListener); - Event.stopObserving(this.options.externalControl, 'mouseover', this.mouseoverListener); - Event.stopObserving(this.options.externalControl, 'mouseout', this.mouseoutListener); - } - } -}; - -Ajax.InPlaceCollectionEditor = Class.create(); -Object.extend(Ajax.InPlaceCollectionEditor.prototype, Ajax.InPlaceEditor.prototype); -Object.extend(Ajax.InPlaceCollectionEditor.prototype, { - createEditField: function() { - if (!this.cached_selectTag) { - var selectTag = document.createElement("select"); - var collection = this.options.collection || []; - var optionTag; - collection.each(function(e,i) { - optionTag = document.createElement("option"); - optionTag.value = (e instanceof Array) ? e[0] : e; - if(this.options.value==optionTag.value) optionTag.selected = true; - optionTag.appendChild(document.createTextNode((e instanceof Array) ? e[1] : e)); - selectTag.appendChild(optionTag); - }.bind(this)); - this.cached_selectTag = selectTag; - } - - this.editField = this.cached_selectTag; - if(this.options.loadTextURL) this.loadExternalText(); - this.form.appendChild(this.editField); - this.options.callback = function(form, value) { - return "value=" + encodeURIComponent(value); - } - } -}); - -// Delayed observer, like Form.Element.Observer, -// but waits for delay after last key input -// Ideal for live-search fields - -Form.Element.DelayedObserver = Class.create(); -Form.Element.DelayedObserver.prototype = { - initialize: function(element, delay, callback) { - this.delay = delay || 0.5; - this.element = $(element); - this.callback = callback; - this.timer = null; - this.lastValue = $F(this.element); - Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); - }, - delayedListener: function(event) { - if(this.lastValue == $F(this.element)) return; - if(this.timer) clearTimeout(this.timer); - this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); - this.lastValue = $F(this.element); - }, - onTimerEvent: function() { - this.timer = null; - this.callback(this.element, $F(this.element)); - } -}; diff --git a/library/cropper/lib/dragdrop.js b/library/cropper/lib/dragdrop.js deleted file mode 100644 index be2a30f53..000000000 --- a/library/cropper/lib/dragdrop.js +++ /dev/null @@ -1,915 +0,0 @@ -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz) -// -// See scriptaculous.js for full license. - -/*--------------------------------------------------------------------------*/ - -var Droppables = { - drops: [], - - remove: function(element) { - this.drops = this.drops.reject(function(d) { return d.element==$(element) }); - }, - - add: function(element) { - element = $(element); - var options = Object.extend({ - greedy: true, - hoverclass: null, - tree: false - }, arguments[1] || {}); - - // cache containers - if(options.containment) { - options._containers = []; - var containment = options.containment; - if((typeof containment == 'object') && - (containment.constructor == Array)) { - containment.each( function(c) { options._containers.push($(c)) }); - } else { - options._containers.push($(containment)); - } - } - - if(options.accept) options.accept = [options.accept].flatten(); - - Element.makePositioned(element); // fix IE - options.element = element; - - this.drops.push(options); - }, - - findDeepestChild: function(drops) { - deepest = drops[0]; - - for (i = 1; i < drops.length; ++i) - if (Element.isParent(drops[i].element, deepest.element)) - deepest = drops[i]; - - return deepest; - }, - - isContained: function(element, drop) { - var containmentNode; - if(drop.tree) { - containmentNode = element.treeNode; - } else { - containmentNode = element.parentNode; - } - return drop._containers.detect(function(c) { return containmentNode == c }); - }, - - isAffected: function(point, element, drop) { - return ( - (drop.element!=element) && - ((!drop._containers) || - this.isContained(element, drop)) && - ((!drop.accept) || - (Element.classNames(element).detect( - function(v) { return drop.accept.include(v) } ) )) && - Position.within(drop.element, point[0], point[1]) ); - }, - - deactivate: function(drop) { - if(drop.hoverclass) - Element.removeClassName(drop.element, drop.hoverclass); - this.last_active = null; - }, - - activate: function(drop) { - if(drop.hoverclass) - Element.addClassName(drop.element, drop.hoverclass); - this.last_active = drop; - }, - - show: function(point, element) { - if(!this.drops.length) return; - var affected = []; - - if(this.last_active) this.deactivate(this.last_active); - this.drops.each( function(drop) { - if(Droppables.isAffected(point, element, drop)) - affected.push(drop); - }); - - if(affected.length>0) { - drop = Droppables.findDeepestChild(affected); - Position.within(drop.element, point[0], point[1]); - if(drop.onHover) - drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); - - Droppables.activate(drop); - } - }, - - fire: function(event, element) { - if(!this.last_active) return; - Position.prepare(); - - if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) - if (this.last_active.onDrop) - this.last_active.onDrop(element, this.last_active.element, event); - }, - - reset: function() { - if(this.last_active) - this.deactivate(this.last_active); - } -} - -var Draggables = { - drags: [], - observers: [], - - register: function(draggable) { - if(this.drags.length == 0) { - this.eventMouseUp = this.endDrag.bindAsEventListener(this); - this.eventMouseMove = this.updateDrag.bindAsEventListener(this); - this.eventKeypress = this.keyPress.bindAsEventListener(this); - - Event.observe(document, "mouseup", this.eventMouseUp); - Event.observe(document, "mousemove", this.eventMouseMove); - Event.observe(document, "keypress", this.eventKeypress); - } - this.drags.push(draggable); - }, - - unregister: function(draggable) { - this.drags = this.drags.reject(function(d) { return d==draggable }); - if(this.drags.length == 0) { - Event.stopObserving(document, "mouseup", this.eventMouseUp); - Event.stopObserving(document, "mousemove", this.eventMouseMove); - Event.stopObserving(document, "keypress", this.eventKeypress); - } - }, - - activate: function(draggable) { - window.focus(); // allows keypress events if window isn't currently focused, fails for Safari - this.activeDraggable = draggable; - }, - - deactivate: function() { - this.activeDraggable = null; - }, - - updateDrag: function(event) { - if(!this.activeDraggable) return; - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - // Mozilla-based browsers fire successive mousemove events with - // the same coordinates, prevent needless redrawing (moz bug?) - if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; - this._lastPointer = pointer; - this.activeDraggable.updateDrag(event, pointer); - }, - - endDrag: function(event) { - if(!this.activeDraggable) return; - this._lastPointer = null; - this.activeDraggable.endDrag(event); - this.activeDraggable = null; - }, - - keyPress: function(event) { - if(this.activeDraggable) - this.activeDraggable.keyPress(event); - }, - - addObserver: function(observer) { - this.observers.push(observer); - this._cacheObserverCallbacks(); - }, - - removeObserver: function(element) { // element instead of observer fixes mem leaks - this.observers = this.observers.reject( function(o) { return o.element==element }); - this._cacheObserverCallbacks(); - }, - - notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' - if(this[eventName+'Count'] > 0) - this.observers.each( function(o) { - if(o[eventName]) o[eventName](eventName, draggable, event); - }); - }, - - _cacheObserverCallbacks: function() { - ['onStart','onEnd','onDrag'].each( function(eventName) { - Draggables[eventName+'Count'] = Draggables.observers.select( - function(o) { return o[eventName]; } - ).length; - }); - } -} - -/*--------------------------------------------------------------------------*/ - -var Draggable = Class.create(); -Draggable.prototype = { - initialize: function(element) { - var options = Object.extend({ - handle: false, - starteffect: function(element) { - element._opacity = Element.getOpacity(element); - new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); - }, - reverteffect: function(element, top_offset, left_offset) { - var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; - element._revert = new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur}); - }, - endeffect: function(element) { - var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0 - new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity}); - }, - zindex: 1000, - revert: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - snap: false // false, or xy or [x,y] or function(x,y){ return [x,y] } - }, arguments[1] || {}); - - this.element = $(element); - - if(options.handle && (typeof options.handle == 'string')) { - var h = Element.childrenWithClassName(this.element, options.handle, true); - if(h.length>0) this.handle = h[0]; - } - if(!this.handle) this.handle = $(options.handle); - if(!this.handle) this.handle = this.element; - - if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) - options.scroll = $(options.scroll); - - Element.makePositioned(this.element); // fix IE - - this.delta = this.currentDelta(); - this.options = options; - this.dragging = false; - - this.eventMouseDown = this.initDrag.bindAsEventListener(this); - Event.observe(this.handle, "mousedown", this.eventMouseDown); - - Draggables.register(this); - }, - - destroy: function() { - Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); - Draggables.unregister(this); - }, - - currentDelta: function() { - return([ - parseInt(Element.getStyle(this.element,'left') || '0'), - parseInt(Element.getStyle(this.element,'top') || '0')]); - }, - - initDrag: function(event) { - if(Event.isLeftClick(event)) { - // abort on form elements, fixes a Firefox issue - var src = Event.element(event); - if(src.tagName && ( - src.tagName=='INPUT' || - src.tagName=='SELECT' || - src.tagName=='OPTION' || - src.tagName=='BUTTON' || - src.tagName=='TEXTAREA')) return; - - if(this.element._revert) { - this.element._revert.cancel(); - this.element._revert = null; - } - - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var pos = Position.cumulativeOffset(this.element); - this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); - - Draggables.activate(this); - Event.stop(event); - } - }, - - startDrag: function(event) { - this.dragging = true; - - if(this.options.zindex) { - this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); - this.element.style.zIndex = this.options.zindex; - } - - if(this.options.ghosting) { - this._clone = this.element.cloneNode(true); - Position.absolutize(this.element); - this.element.parentNode.insertBefore(this._clone, this.element); - } - - if(this.options.scroll) { - if (this.options.scroll == window) { - var where = this._getWindowScroll(this.options.scroll); - this.originalScrollLeft = where.left; - this.originalScrollTop = where.top; - } else { - this.originalScrollLeft = this.options.scroll.scrollLeft; - this.originalScrollTop = this.options.scroll.scrollTop; - } - } - - Draggables.notify('onStart', this, event); - if(this.options.starteffect) this.options.starteffect(this.element); - }, - - updateDrag: function(event, pointer) { - if(!this.dragging) this.startDrag(event); - Position.prepare(); - Droppables.show(pointer, this.element); - Draggables.notify('onDrag', this, event); - this.draw(pointer); - if(this.options.change) this.options.change(this); - - if(this.options.scroll) { - this.stopScrolling(); - - var p; - if (this.options.scroll == window) { - with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } - } else { - p = Position.page(this.options.scroll); - p[0] += this.options.scroll.scrollLeft; - p[1] += this.options.scroll.scrollTop; - p.push(p[0]+this.options.scroll.offsetWidth); - p.push(p[1]+this.options.scroll.offsetHeight); - } - var speed = [0,0]; - if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); - if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); - if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); - if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); - this.startScrolling(speed); - } - - // fix AppleWebKit rendering - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); - - Event.stop(event); - }, - - finishDrag: function(event, success) { - this.dragging = false; - - if(this.options.ghosting) { - Position.relativize(this.element); - Element.remove(this._clone); - this._clone = null; - } - - if(success) Droppables.fire(event, this.element); - Draggables.notify('onEnd', this, event); - - var revert = this.options.revert; - if(revert && typeof revert == 'function') revert = revert(this.element); - - var d = this.currentDelta(); - if(revert && this.options.reverteffect) { - this.options.reverteffect(this.element, - d[1]-this.delta[1], d[0]-this.delta[0]); - } else { - this.delta = d; - } - - if(this.options.zindex) - this.element.style.zIndex = this.originalZ; - - if(this.options.endeffect) - this.options.endeffect(this.element); - - Draggables.deactivate(this); - Droppables.reset(); - }, - - keyPress: function(event) { - if(event.keyCode!=Event.KEY_ESC) return; - this.finishDrag(event, false); - Event.stop(event); - }, - - endDrag: function(event) { - if(!this.dragging) return; - this.stopScrolling(); - this.finishDrag(event, true); - Event.stop(event); - }, - - draw: function(point) { - var pos = Position.cumulativeOffset(this.element); - var d = this.currentDelta(); - pos[0] -= d[0]; pos[1] -= d[1]; - - if(this.options.scroll && (this.options.scroll != window)) { - pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; - pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; - } - - var p = [0,1].map(function(i){ - return (point[i]-pos[i]-this.offset[i]) - }.bind(this)); - - if(this.options.snap) { - if(typeof this.options.snap == 'function') { - p = this.options.snap(p[0],p[1],this); - } else { - if(this.options.snap instanceof Array) { - p = p.map( function(v, i) { - return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this)) - } else { - p = p.map( function(v) { - return Math.round(v/this.options.snap)*this.options.snap }.bind(this)) - } - }} - - var style = this.element.style; - if((!this.options.constraint) || (this.options.constraint=='horizontal')) - style.left = p[0] + "px"; - if((!this.options.constraint) || (this.options.constraint=='vertical')) - style.top = p[1] + "px"; - if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering - }, - - stopScrolling: function() { - if(this.scrollInterval) { - clearInterval(this.scrollInterval); - this.scrollInterval = null; - Draggables._lastScrollPointer = null; - } - }, - - startScrolling: function(speed) { - this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; - this.lastScrolled = new Date(); - this.scrollInterval = setInterval(this.scroll.bind(this), 10); - }, - - scroll: function() { - var current = new Date(); - var delta = current - this.lastScrolled; - this.lastScrolled = current; - if(this.options.scroll == window) { - with (this._getWindowScroll(this.options.scroll)) { - if (this.scrollSpeed[0] || this.scrollSpeed[1]) { - var d = delta / 1000; - this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); - } - } - } else { - this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; - this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; - } - - Position.prepare(); - Droppables.show(Draggables._lastPointer, this.element); - Draggables.notify('onDrag', this); - Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); - Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; - Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; - if (Draggables._lastScrollPointer[0] < 0) - Draggables._lastScrollPointer[0] = 0; - if (Draggables._lastScrollPointer[1] < 0) - Draggables._lastScrollPointer[1] = 0; - this.draw(Draggables._lastScrollPointer); - - if(this.options.change) this.options.change(this); - }, - - _getWindowScroll: function(w) { - var T, L, W, H; - with (w.document) { - if (w.document.documentElement && documentElement.scrollTop) { - T = documentElement.scrollTop; - L = documentElement.scrollLeft; - } else if (w.document.body) { - T = body.scrollTop; - L = body.scrollLeft; - } - if (w.innerWidth) { - W = w.innerWidth; - H = w.innerHeight; - } else if (w.document.documentElement && documentElement.clientWidth) { - W = documentElement.clientWidth; - H = documentElement.clientHeight; - } else { - W = body.offsetWidth; - H = body.offsetHeight - } - } - return { top: T, left: L, width: W, height: H }; - } -} - -/*--------------------------------------------------------------------------*/ - -var SortableObserver = Class.create(); -SortableObserver.prototype = { - initialize: function(element, observer) { - this.element = $(element); - this.observer = observer; - this.lastValue = Sortable.serialize(this.element); - }, - - onStart: function() { - this.lastValue = Sortable.serialize(this.element); - }, - - onEnd: function() { - Sortable.unmark(); - if(this.lastValue != Sortable.serialize(this.element)) - this.observer(this.element) - } -} - -var Sortable = { - sortables: {}, - - _findRootElement: function(element) { - while (element.tagName != "BODY") { - if(element.id && Sortable.sortables[element.id]) return element; - element = element.parentNode; - } - }, - - options: function(element) { - element = Sortable._findRootElement($(element)); - if(!element) return; - return Sortable.sortables[element.id]; - }, - - destroy: function(element){ - var s = Sortable.options(element); - - if(s) { - Draggables.removeObserver(s.element); - s.droppables.each(function(d){ Droppables.remove(d) }); - s.draggables.invoke('destroy'); - - delete Sortable.sortables[s.element.id]; - } - }, - - create: function(element) { - element = $(element); - var options = Object.extend({ - element: element, - tag: 'li', // assumes li children, override with tag: 'tagname' - dropOnEmpty: false, - tree: false, - treeTag: 'ul', - overlap: 'vertical', // one of 'vertical', 'horizontal' - constraint: 'vertical', // one of 'vertical', 'horizontal', false - containment: element, // also takes array of elements (or id's); or false - handle: false, // or a CSS class - only: false, - hoverclass: null, - ghosting: false, - scroll: false, - scrollSensitivity: 20, - scrollSpeed: 15, - format: /^[^_]*_(.*)$/, - onChange: Prototype.emptyFunction, - onUpdate: Prototype.emptyFunction - }, arguments[1] || {}); - - // clear any old sortable with same element - this.destroy(element); - - // build options for the draggables - var options_for_draggable = { - revert: true, - scroll: options.scroll, - scrollSpeed: options.scrollSpeed, - scrollSensitivity: options.scrollSensitivity, - ghosting: options.ghosting, - constraint: options.constraint, - handle: options.handle }; - - if(options.starteffect) - options_for_draggable.starteffect = options.starteffect; - - if(options.reverteffect) - options_for_draggable.reverteffect = options.reverteffect; - else - if(options.ghosting) options_for_draggable.reverteffect = function(element) { - element.style.top = 0; - element.style.left = 0; - }; - - if(options.endeffect) - options_for_draggable.endeffect = options.endeffect; - - if(options.zindex) - options_for_draggable.zindex = options.zindex; - - // build options for the droppables - var options_for_droppable = { - overlap: options.overlap, - containment: options.containment, - tree: options.tree, - hoverclass: options.hoverclass, - onHover: Sortable.onHover - //greedy: !options.dropOnEmpty - } - - var options_for_tree = { - onHover: Sortable.onEmptyHover, - overlap: options.overlap, - containment: options.containment, - hoverclass: options.hoverclass - } - - // fix for gecko engine - Element.cleanWhitespace(element); - - options.draggables = []; - options.droppables = []; - - // drop on empty handling - if(options.dropOnEmpty || options.tree) { - Droppables.add(element, options_for_tree); - options.droppables.push(element); - } - - (this.findElements(element, options) || []).each( function(e) { - // handles are per-draggable - var handle = options.handle ? - Element.childrenWithClassName(e, options.handle)[0] : e; - options.draggables.push( - new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); - Droppables.add(e, options_for_droppable); - if(options.tree) e.treeNode = element; - options.droppables.push(e); - }); - - if(options.tree) { - (Sortable.findTreeElements(element, options) || []).each( function(e) { - Droppables.add(e, options_for_tree); - e.treeNode = element; - options.droppables.push(e); - }); - } - - // keep reference - this.sortables[element.id] = options; - - // for onupdate - Draggables.addObserver(new SortableObserver(element, options.onUpdate)); - - }, - - // return all suitable-for-sortable elements in a guaranteed order - findElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.tag); - }, - - findTreeElements: function(element, options) { - return Element.findChildren( - element, options.only, options.tree ? true : false, options.treeTag); - }, - - onHover: function(element, dropon, overlap) { - if(Element.isParent(dropon, element)) return; - - if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { - return; - } else if(overlap>0.5) { - Sortable.mark(dropon, 'before'); - if(dropon.previousSibling != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, dropon); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } else { - Sortable.mark(dropon, 'after'); - var nextElement = dropon.nextSibling || null; - if(nextElement != element) { - var oldParentNode = element.parentNode; - element.style.visibility = "hidden"; // fix gecko rendering - dropon.parentNode.insertBefore(element, nextElement); - if(dropon.parentNode!=oldParentNode) - Sortable.options(oldParentNode).onChange(element); - Sortable.options(dropon.parentNode).onChange(element); - } - } - }, - - onEmptyHover: function(element, dropon, overlap) { - var oldParentNode = element.parentNode; - var droponOptions = Sortable.options(dropon); - - if(!Element.isParent(dropon, element)) { - var index; - - var children = Sortable.findElements(dropon, {tag: droponOptions.tag}); - var child = null; - - if(children) { - var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); - - for (index = 0; index < children.length; index += 1) { - if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { - offset -= Element.offsetSize (children[index], droponOptions.overlap); - } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { - child = index + 1 < children.length ? children[index + 1] : null; - break; - } else { - child = children[index]; - break; - } - } - } - - dropon.insertBefore(element, child); - - Sortable.options(oldParentNode).onChange(element); - droponOptions.onChange(element); - } - }, - - unmark: function() { - if(Sortable._marker) Element.hide(Sortable._marker); - }, - - mark: function(dropon, position) { - // mark on ghosting only - var sortable = Sortable.options(dropon.parentNode); - if(sortable && !sortable.ghosting) return; - - if(!Sortable._marker) { - Sortable._marker = $('dropmarker') || document.createElement('DIV'); - Element.hide(Sortable._marker); - Element.addClassName(Sortable._marker, 'dropmarker'); - Sortable._marker.style.position = 'absolute'; - document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); - } - var offsets = Position.cumulativeOffset(dropon); - Sortable._marker.style.left = offsets[0] + 'px'; - Sortable._marker.style.top = offsets[1] + 'px'; - - if(position=='after') - if(sortable.overlap == 'horizontal') - Sortable._marker.style.left = (offsets[0]+dropon.clientWidth) + 'px'; - else - Sortable._marker.style.top = (offsets[1]+dropon.clientHeight) + 'px'; - - Element.show(Sortable._marker); - }, - - _tree: function(element, options, parent) { - var children = Sortable.findElements(element, options) || []; - - for (var i = 0; i < children.length; ++i) { - var match = children[i].id.match(options.format); - - if (!match) continue; - - var child = { - id: encodeURIComponent(match ? match[1] : null), - element: element, - parent: parent, - children: new Array, - position: parent.children.length, - container: Sortable._findChildrenElement(children[i], options.treeTag.toUpperCase()) - } - - /* Get the element containing the children and recurse over it */ - if (child.container) - this._tree(child.container, options, child) - - parent.children.push (child); - } - - return parent; - }, - - /* Finds the first element of the given tag type within a parent element. - Used for finding the first LI[ST] within a L[IST]I[TEM].*/ - _findChildrenElement: function (element, containerTag) { - if (element && element.hasChildNodes) - for (var i = 0; i < element.childNodes.length; ++i) - if (element.childNodes[i].tagName == containerTag) - return element.childNodes[i]; - - return null; - }, - - tree: function(element) { - element = $(element); - var sortableOptions = this.options(element); - var options = Object.extend({ - tag: sortableOptions.tag, - treeTag: sortableOptions.treeTag, - only: sortableOptions.only, - name: element.id, - format: sortableOptions.format - }, arguments[1] || {}); - - var root = { - id: null, - parent: null, - children: new Array, - container: element, - position: 0 - } - - return Sortable._tree (element, options, root); - }, - - /* Construct a [i] index for a particular node */ - _constructIndex: function(node) { - var index = ''; - do { - if (node.id) index = '[' + node.position + ']' + index; - } while ((node = node.parent) != null); - return index; - }, - - sequence: function(element) { - element = $(element); - var options = Object.extend(this.options(element), arguments[1] || {}); - - return $(this.findElements(element, options) || []).map( function(item) { - return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; - }); - }, - - setSequence: function(element, new_sequence) { - element = $(element); - var options = Object.extend(this.options(element), arguments[2] || {}); - - var nodeMap = {}; - this.findElements(element, options).each( function(n) { - if (n.id.match(options.format)) - nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; - n.parentNode.removeChild(n); - }); - - new_sequence.each(function(ident) { - var n = nodeMap[ident]; - if (n) { - n[1].appendChild(n[0]); - delete nodeMap[ident]; - } - }); - }, - - serialize: function(element) { - element = $(element); - var options = Object.extend(Sortable.options(element), arguments[1] || {}); - var name = encodeURIComponent( - (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); - - if (options.tree) { - return Sortable.tree(element, arguments[1]).children.map( function (item) { - return [name + Sortable._constructIndex(item) + "=" + - encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); - }).flatten().join('&'); - } else { - return Sortable.sequence(element, arguments[1]).map( function(item) { - return name + "[]=" + encodeURIComponent(item); - }).join('&'); - } - } -} - -/* Returns true if child is contained within element */ -Element.isParent = function(child, element) { - if (!child.parentNode || child == element) return false; - - if (child.parentNode == element) return true; - - return Element.isParent(child.parentNode, element); -} - -Element.findChildren = function(element, only, recursive, tagName) { - if(!element.hasChildNodes()) return null; - tagName = tagName.toUpperCase(); - if(only) only = [only].flatten(); - var elements = []; - $A(element.childNodes).each( function(e) { - if(e.tagName && e.tagName.toUpperCase()==tagName && - (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) - elements.push(e); - if(recursive) { - var grandchildren = Element.findChildren(e, only, recursive, tagName); - if(grandchildren) elements.push(grandchildren); - } - }); - - return (elements.length>0 ? elements.flatten() : []); -} - -Element.offsetSize = function (element, type) { - if (type == 'vertical' || type == 'height') - return element.offsetHeight; - else - return element.offsetWidth; -} \ No newline at end of file diff --git a/library/cropper/lib/effects.js b/library/cropper/lib/effects.js deleted file mode 100644 index 0864323ec..000000000 --- a/library/cropper/lib/effects.js +++ /dev/null @@ -1,958 +0,0 @@ -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// Contributors: -// Justin Palmer (http://encytemedia.com/) -// Mark Pilgrim (http://diveintomark.org/) -// Martin Bialasinki -// -// See scriptaculous.js for full license. - -// converts rgb() and #xxx to #xxxxxx format, -// returns self (or first argument) if not convertable -String.prototype.parseColor = function() { - var color = '#'; - if(this.slice(0,4) == 'rgb(') { - var cols = this.slice(4,this.length-1).split(','); - var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); - } else { - if(this.slice(0,1) == '#') { - if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); - if(this.length==7) color = this.toLowerCase(); - } - } - return(color.length==7 ? color : (arguments[0] || this)); -} - -/*--------------------------------------------------------------------------*/ - -Element.collectTextNodes = function(element) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); - }).flatten().join(''); -} - -Element.collectTextNodesIgnoreClass = function(element, className) { - return $A($(element).childNodes).collect( function(node) { - return (node.nodeType==3 ? node.nodeValue : - ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? - Element.collectTextNodesIgnoreClass(node, className) : '')); - }).flatten().join(''); -} - -Element.setContentZoom = function(element, percent) { - element = $(element); - Element.setStyle(element, {fontSize: (percent/100) + 'em'}); - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); -} - -Element.getOpacity = function(element){ - var opacity; - if (opacity = Element.getStyle(element, 'opacity')) - return parseFloat(opacity); - if (opacity = (Element.getStyle(element, 'filter') || '').match(/alpha\(opacity=(.*)\)/)) - if(opacity[1]) return parseFloat(opacity[1]) / 100; - return 1.0; -} - -Element.setOpacity = function(element, value){ - element= $(element); - if (value == 1){ - Element.setStyle(element, { opacity: - (/Gecko/.test(navigator.userAgent) && !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? - 0.999999 : null }); - if(/MSIE/.test(navigator.userAgent)) - Element.setStyle(element, {filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'')}); - } else { - if(value < 0.00001) value = 0; - Element.setStyle(element, {opacity: value}); - if(/MSIE/.test(navigator.userAgent)) - Element.setStyle(element, - { filter: Element.getStyle(element,'filter').replace(/alpha\([^\)]*\)/gi,'') + - 'alpha(opacity='+value*100+')' }); - } -} - -Element.getInlineOpacity = function(element){ - return $(element).style.opacity || ''; -} - -Element.childrenWithClassName = function(element, className, findFirst) { - var classNameRegExp = new RegExp("(^|\\s)" + className + "(\\s|$)"); - var results = $A($(element).getElementsByTagName('*'))[findFirst ? 'detect' : 'select']( function(c) { - return (c.className && c.className.match(classNameRegExp)); - }); - if(!results) results = []; - return results; -} - -Element.forceRerendering = function(element) { - try { - element = $(element); - var n = document.createTextNode(' '); - element.appendChild(n); - element.removeChild(n); - } catch(e) { } -}; - -/*--------------------------------------------------------------------------*/ - -Array.prototype.call = function() { - var args = arguments; - this.each(function(f){ f.apply(this, args) }); -} - -/*--------------------------------------------------------------------------*/ - -var Effect = { - tagifyText: function(element) { - var tagifyStyle = 'position:relative'; - if(/MSIE/.test(navigator.userAgent)) tagifyStyle += ';zoom:1'; - element = $(element); - $A(element.childNodes).each( function(child) { - if(child.nodeType==3) { - child.nodeValue.toArray().each( function(character) { - element.insertBefore( - Builder.node('span',{style: tagifyStyle}, - character == ' ' ? String.fromCharCode(160) : character), - child); - }); - Element.remove(child); - } - }); - }, - multiple: function(element, effect) { - var elements; - if(((typeof element == 'object') || - (typeof element == 'function')) && - (element.length)) - elements = element; - else - elements = $(element).childNodes; - - var options = Object.extend({ - speed: 0.1, - delay: 0.0 - }, arguments[2] || {}); - var masterDelay = options.delay; - - $A(elements).each( function(element, index) { - new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); - }); - }, - PAIRS: { - 'slide': ['SlideDown','SlideUp'], - 'blind': ['BlindDown','BlindUp'], - 'appear': ['Appear','Fade'] - }, - toggle: function(element, effect) { - element = $(element); - effect = (effect || 'appear').toLowerCase(); - var options = Object.extend({ - queue: { position:'end', scope:(element.id || 'global'), limit: 1 } - }, arguments[2] || {}); - Effect[element.visible() ? - Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options); - } -}; - -var Effect2 = Effect; // deprecated - -/* ------------- transitions ------------- */ - -Effect.Transitions = {} - -Effect.Transitions.linear = function(pos) { - return pos; -} -Effect.Transitions.sinoidal = function(pos) { - return (-Math.cos(pos*Math.PI)/2) + 0.5; -} -Effect.Transitions.reverse = function(pos) { - return 1-pos; -} -Effect.Transitions.flicker = function(pos) { - return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4; -} -Effect.Transitions.wobble = function(pos) { - return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5; -} -Effect.Transitions.pulse = function(pos) { - return (Math.floor(pos*10) % 2 == 0 ? - (pos*10-Math.floor(pos*10)) : 1-(pos*10-Math.floor(pos*10))); -} -Effect.Transitions.none = function(pos) { - return 0; -} -Effect.Transitions.full = function(pos) { - return 1; -} - -/* ------------- core effects ------------- */ - -Effect.ScopedQueue = Class.create(); -Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), { - initialize: function() { - this.effects = []; - this.interval = null; - }, - _each: function(iterator) { - this.effects._each(iterator); - }, - add: function(effect) { - var timestamp = new Date().getTime(); - - var position = (typeof effect.options.queue == 'string') ? - effect.options.queue : effect.options.queue.position; - - switch(position) { - case 'front': - // move unstarted effects after this effect - this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { - e.startOn += effect.finishOn; - e.finishOn += effect.finishOn; - }); - break; - case 'end': - // start effect after last queued effect has finished - timestamp = this.effects.pluck('finishOn').max() || timestamp; - break; - } - - effect.startOn += timestamp; - effect.finishOn += timestamp; - - if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) - this.effects.push(effect); - - if(!this.interval) - this.interval = setInterval(this.loop.bind(this), 40); - }, - remove: function(effect) { - this.effects = this.effects.reject(function(e) { return e==effect }); - if(this.effects.length == 0) { - clearInterval(this.interval); - this.interval = null; - } - }, - loop: function() { - var timePos = new Date().getTime(); - this.effects.invoke('loop', timePos); - } -}); - -Effect.Queues = { - instances: $H(), - get: function(queueName) { - if(typeof queueName != 'string') return queueName; - - if(!this.instances[queueName]) - this.instances[queueName] = new Effect.ScopedQueue(); - - return this.instances[queueName]; - } -} -Effect.Queue = Effect.Queues.get('global'); - -Effect.DefaultOptions = { - transition: Effect.Transitions.sinoidal, - duration: 1.0, // seconds - fps: 25.0, // max. 25fps due to Effect.Queue implementation - sync: false, // true for combining - from: 0.0, - to: 1.0, - delay: 0.0, - queue: 'parallel' -} - -Effect.Base = function() {}; -Effect.Base.prototype = { - position: null, - start: function(options) { - this.options = Object.extend(Object.extend({},Effect.DefaultOptions), options || {}); - this.currentFrame = 0; - this.state = 'idle'; - this.startOn = this.options.delay*1000; - this.finishOn = this.startOn + (this.options.duration*1000); - this.event('beforeStart'); - if(!this.options.sync) - Effect.Queues.get(typeof this.options.queue == 'string' ? - 'global' : this.options.queue.scope).add(this); - }, - loop: function(timePos) { - if(timePos >= this.startOn) { - if(timePos >= this.finishOn) { - this.render(1.0); - this.cancel(); - this.event('beforeFinish'); - if(this.finish) this.finish(); - this.event('afterFinish'); - return; - } - var pos = (timePos - this.startOn) / (this.finishOn - this.startOn); - var frame = Math.round(pos * this.options.fps * this.options.duration); - if(frame > this.currentFrame) { - this.render(pos); - this.currentFrame = frame; - } - } - }, - render: function(pos) { - if(this.state == 'idle') { - this.state = 'running'; - this.event('beforeSetup'); - if(this.setup) this.setup(); - this.event('afterSetup'); - } - if(this.state == 'running') { - if(this.options.transition) pos = this.options.transition(pos); - pos *= (this.options.to-this.options.from); - pos += this.options.from; - this.position = pos; - this.event('beforeUpdate'); - if(this.update) this.update(pos); - this.event('afterUpdate'); - } - }, - cancel: function() { - if(!this.options.sync) - Effect.Queues.get(typeof this.options.queue == 'string' ? - 'global' : this.options.queue.scope).remove(this); - this.state = 'finished'; - }, - event: function(eventName) { - if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); - if(this.options[eventName]) this.options[eventName](this); - }, - inspect: function() { - return '#'; - } -} - -Effect.Parallel = Class.create(); -Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), { - initialize: function(effects) { - this.effects = effects || []; - this.start(arguments[1]); - }, - update: function(position) { - this.effects.invoke('render', position); - }, - finish: function(position) { - this.effects.each( function(effect) { - effect.render(1.0); - effect.cancel(); - effect.event('beforeFinish'); - if(effect.finish) effect.finish(position); - effect.event('afterFinish'); - }); - } -}); - -Effect.Opacity = Class.create(); -Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - // make this work on IE on elements without 'layout' - if(/MSIE/.test(navigator.userAgent) && (!this.element.hasLayout)) - this.element.setStyle({zoom: 1}); - var options = Object.extend({ - from: this.element.getOpacity() || 0.0, - to: 1.0 - }, arguments[1] || {}); - this.start(options); - }, - update: function(position) { - this.element.setOpacity(position); - } -}); - -Effect.Move = Class.create(); -Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - var options = Object.extend({ - x: 0, - y: 0, - mode: 'relative' - }, arguments[1] || {}); - this.start(options); - }, - setup: function() { - // Bug in Opera: Opera returns the "real" position of a static element or - // relative element that does not have top/left explicitly set. - // ==> Always set top and left for position relative elements in your stylesheets - // (to 0 if you do not need them) - this.element.makePositioned(); - this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); - this.originalTop = parseFloat(this.element.getStyle('top') || '0'); - if(this.options.mode == 'absolute') { - // absolute movement, so we need to calc deltaX and deltaY - this.options.x = this.options.x - this.originalLeft; - this.options.y = this.options.y - this.originalTop; - } - }, - update: function(position) { - this.element.setStyle({ - left: this.options.x * position + this.originalLeft + 'px', - top: this.options.y * position + this.originalTop + 'px' - }); - } -}); - -// for backwards compatibility -Effect.MoveBy = function(element, toTop, toLeft) { - return new Effect.Move(element, - Object.extend({ x: toLeft, y: toTop }, arguments[3] || {})); -}; - -Effect.Scale = Class.create(); -Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), { - initialize: function(element, percent) { - this.element = $(element) - var options = Object.extend({ - scaleX: true, - scaleY: true, - scaleContent: true, - scaleFromCenter: false, - scaleMode: 'box', // 'box' or 'contents' or {} with provided values - scaleFrom: 100.0, - scaleTo: percent - }, arguments[2] || {}); - this.start(options); - }, - setup: function() { - this.restoreAfterFinish = this.options.restoreAfterFinish || false; - this.elementPositioning = this.element.getStyle('position'); - - this.originalStyle = {}; - ['top','left','width','height','fontSize'].each( function(k) { - this.originalStyle[k] = this.element.style[k]; - }.bind(this)); - - this.originalTop = this.element.offsetTop; - this.originalLeft = this.element.offsetLeft; - - var fontSize = this.element.getStyle('font-size') || '100%'; - ['em','px','%'].each( function(fontSizeType) { - if(fontSize.indexOf(fontSizeType)>0) { - this.fontSize = parseFloat(fontSize); - this.fontSizeType = fontSizeType; - } - }.bind(this)); - - this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; - - this.dims = null; - if(this.options.scaleMode=='box') - this.dims = [this.element.offsetHeight, this.element.offsetWidth]; - if(/^content/.test(this.options.scaleMode)) - this.dims = [this.element.scrollHeight, this.element.scrollWidth]; - if(!this.dims) - this.dims = [this.options.scaleMode.originalHeight, - this.options.scaleMode.originalWidth]; - }, - update: function(position) { - var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); - if(this.options.scaleContent && this.fontSize) - this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); - this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); - }, - finish: function(position) { - if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); - }, - setDimensions: function(height, width) { - var d = {}; - if(this.options.scaleX) d.width = width + 'px'; - if(this.options.scaleY) d.height = height + 'px'; - if(this.options.scaleFromCenter) { - var topd = (height - this.dims[0])/2; - var leftd = (width - this.dims[1])/2; - if(this.elementPositioning == 'absolute') { - if(this.options.scaleY) d.top = this.originalTop-topd + 'px'; - if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; - } else { - if(this.options.scaleY) d.top = -topd + 'px'; - if(this.options.scaleX) d.left = -leftd + 'px'; - } - } - this.element.setStyle(d); - } -}); - -Effect.Highlight = Class.create(); -Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {}); - this.start(options); - }, - setup: function() { - // Prevent executing on elements not in the layout flow - if(this.element.getStyle('display')=='none') { this.cancel(); return; } - // Disable background image during the effect - this.oldStyle = { - backgroundImage: this.element.getStyle('background-image') }; - this.element.setStyle({backgroundImage: 'none'}); - if(!this.options.endcolor) - this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); - if(!this.options.restorecolor) - this.options.restorecolor = this.element.getStyle('background-color'); - // init color calculations - this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); - this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); - }, - update: function(position) { - this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ - return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) }); - }, - finish: function() { - this.element.setStyle(Object.extend(this.oldStyle, { - backgroundColor: this.options.restorecolor - })); - } -}); - -Effect.ScrollTo = Class.create(); -Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), { - initialize: function(element) { - this.element = $(element); - this.start(arguments[1] || {}); - }, - setup: function() { - Position.prepare(); - var offsets = Position.cumulativeOffset(this.element); - if(this.options.offset) offsets[1] += this.options.offset; - var max = window.innerHeight ? - window.height - window.innerHeight : - document.body.scrollHeight - - (document.documentElement.clientHeight ? - document.documentElement.clientHeight : document.body.clientHeight); - this.scrollStart = Position.deltaY; - this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart; - }, - update: function(position) { - Position.prepare(); - window.scrollTo(Position.deltaX, - this.scrollStart + (position*this.delta)); - } -}); - -/* ------------- combination effects ------------- */ - -Effect.Fade = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - var options = Object.extend({ - from: element.getOpacity() || 1.0, - to: 0.0, - afterFinishInternal: function(effect) { - if(effect.options.to!=0) return; - effect.element.hide(); - effect.element.setStyle({opacity: oldOpacity}); - }}, arguments[1] || {}); - return new Effect.Opacity(element,options); -} - -Effect.Appear = function(element) { - element = $(element); - var options = Object.extend({ - from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), - to: 1.0, - // force Safari to render floated elements properly - afterFinishInternal: function(effect) { - effect.element.forceRerendering(); - }, - beforeSetup: function(effect) { - effect.element.setOpacity(effect.options.from); - effect.element.show(); - }}, arguments[1] || {}); - return new Effect.Opacity(element,options); -} - -Effect.Puff = function(element) { - element = $(element); - var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position') }; - return new Effect.Parallel( - [ new Effect.Scale(element, 200, - { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], - Object.extend({ duration: 1.0, - beforeSetupInternal: function(effect) { - effect.effects[0].element.setStyle({position: 'absolute'}); }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide(); - effect.effects[0].element.setStyle(oldStyle); } - }, arguments[1] || {}) - ); -} - -Effect.BlindUp = function(element) { - element = $(element); - element.makeClipping(); - return new Effect.Scale(element, 0, - Object.extend({ scaleContent: false, - scaleX: false, - restoreAfterFinish: true, - afterFinishInternal: function(effect) { - effect.element.hide(); - effect.element.undoClipping(); - } - }, arguments[1] || {}) - ); -} - -Effect.BlindDown = function(element) { - element = $(element); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, - Object.extend({ scaleContent: false, - scaleX: false, - scaleFrom: 0, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makeClipping(); - effect.element.setStyle({height: '0px'}); - effect.element.show(); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping(); - } - }, arguments[1] || {}) - ); -} - -Effect.SwitchOff = function(element) { - element = $(element); - var oldOpacity = element.getInlineOpacity(); - return new Effect.Appear(element, { - duration: 0.4, - from: 0, - transition: Effect.Transitions.flicker, - afterFinishInternal: function(effect) { - new Effect.Scale(effect.element, 1, { - duration: 0.3, scaleFromCenter: true, - scaleX: false, scaleContent: false, restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makePositioned(); - effect.element.makeClipping(); - }, - afterFinishInternal: function(effect) { - effect.element.hide(); - effect.element.undoClipping(); - effect.element.undoPositioned(); - effect.element.setStyle({opacity: oldOpacity}); - } - }) - } - }); -} - -Effect.DropOut = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left'), - opacity: element.getInlineOpacity() }; - return new Effect.Parallel( - [ new Effect.Move(element, {x: 0, y: 100, sync: true }), - new Effect.Opacity(element, { sync: true, to: 0.0 }) ], - Object.extend( - { duration: 0.5, - beforeSetup: function(effect) { - effect.effects[0].element.makePositioned(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide(); - effect.effects[0].element.undoPositioned(); - effect.effects[0].element.setStyle(oldStyle); - } - }, arguments[1] || {})); -} - -Effect.Shake = function(element) { - element = $(element); - var oldStyle = { - top: element.getStyle('top'), - left: element.getStyle('left') }; - return new Effect.Move(element, - { x: 20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: 40, y: 0, duration: 0.1, afterFinishInternal: function(effect) { - new Effect.Move(effect.element, - { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) { - effect.element.undoPositioned(); - effect.element.setStyle(oldStyle); - }}) }}) }}) }}) }}) }}); -} - -Effect.SlideDown = function(element) { - element = $(element); - element.cleanWhitespace(); - // SlideDown need to have the content of the element wrapped in a container element with fixed height! - var oldInnerBottom = $(element.firstChild).getStyle('bottom'); - var elementDimensions = element.getDimensions(); - return new Effect.Scale(element, 100, Object.extend({ - scaleContent: false, - scaleX: false, - scaleFrom: window.opera ? 0 : 1, - scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, - restoreAfterFinish: true, - afterSetup: function(effect) { - effect.element.makePositioned(); - effect.element.firstChild.makePositioned(); - if(window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping(); - effect.element.setStyle({height: '0px'}); - effect.element.show(); }, - afterUpdateInternal: function(effect) { - effect.element.firstChild.setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); - }, - afterFinishInternal: function(effect) { - effect.element.undoClipping(); - // IE will crash if child is undoPositioned first - if(/MSIE/.test(navigator.userAgent)){ - effect.element.undoPositioned(); - effect.element.firstChild.undoPositioned(); - }else{ - effect.element.firstChild.undoPositioned(); - effect.element.undoPositioned(); - } - effect.element.firstChild.setStyle({bottom: oldInnerBottom}); } - }, arguments[1] || {}) - ); -} - -Effect.SlideUp = function(element) { - element = $(element); - element.cleanWhitespace(); - var oldInnerBottom = $(element.firstChild).getStyle('bottom'); - return new Effect.Scale(element, window.opera ? 0 : 1, - Object.extend({ scaleContent: false, - scaleX: false, - scaleMode: 'box', - scaleFrom: 100, - restoreAfterFinish: true, - beforeStartInternal: function(effect) { - effect.element.makePositioned(); - effect.element.firstChild.makePositioned(); - if(window.opera) effect.element.setStyle({top: ''}); - effect.element.makeClipping(); - effect.element.show(); }, - afterUpdateInternal: function(effect) { - effect.element.firstChild.setStyle({bottom: - (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, - afterFinishInternal: function(effect) { - effect.element.hide(); - effect.element.undoClipping(); - effect.element.firstChild.undoPositioned(); - effect.element.undoPositioned(); - effect.element.setStyle({bottom: oldInnerBottom}); } - }, arguments[1] || {}) - ); -} - -// Bug in opera makes the TD containing this element expand for a instance after finish -Effect.Squish = function(element) { - return new Effect.Scale(element, window.opera ? 1 : 0, - { restoreAfterFinish: true, - beforeSetup: function(effect) { - effect.element.makeClipping(effect.element); }, - afterFinishInternal: function(effect) { - effect.element.hide(effect.element); - effect.element.undoClipping(effect.element); } - }); -} - -Effect.Grow = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.full - }, arguments[1] || {}); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var initialMoveX, initialMoveY; - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - initialMoveX = initialMoveY = moveX = moveY = 0; - break; - case 'top-right': - initialMoveX = dims.width; - initialMoveY = moveY = 0; - moveX = -dims.width; - break; - case 'bottom-left': - initialMoveX = moveX = 0; - initialMoveY = dims.height; - moveY = -dims.height; - break; - case 'bottom-right': - initialMoveX = dims.width; - initialMoveY = dims.height; - moveX = -dims.width; - moveY = -dims.height; - break; - case 'center': - initialMoveX = dims.width / 2; - initialMoveY = dims.height / 2; - moveX = -dims.width / 2; - moveY = -dims.height / 2; - break; - } - - return new Effect.Move(element, { - x: initialMoveX, - y: initialMoveY, - duration: 0.01, - beforeSetup: function(effect) { - effect.element.hide(); - effect.element.makeClipping(); - effect.element.makePositioned(); - }, - afterFinishInternal: function(effect) { - new Effect.Parallel( - [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), - new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), - new Effect.Scale(effect.element, 100, { - scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, - sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) - ], Object.extend({ - beforeSetup: function(effect) { - effect.effects[0].element.setStyle({height: '0px'}); - effect.effects[0].element.show(); - }, - afterFinishInternal: function(effect) { - effect.effects[0].element.undoClipping(); - effect.effects[0].element.undoPositioned(); - effect.effects[0].element.setStyle(oldStyle); - } - }, options) - ) - } - }); -} - -Effect.Shrink = function(element) { - element = $(element); - var options = Object.extend({ - direction: 'center', - moveTransition: Effect.Transitions.sinoidal, - scaleTransition: Effect.Transitions.sinoidal, - opacityTransition: Effect.Transitions.none - }, arguments[1] || {}); - var oldStyle = { - top: element.style.top, - left: element.style.left, - height: element.style.height, - width: element.style.width, - opacity: element.getInlineOpacity() }; - - var dims = element.getDimensions(); - var moveX, moveY; - - switch (options.direction) { - case 'top-left': - moveX = moveY = 0; - break; - case 'top-right': - moveX = dims.width; - moveY = 0; - break; - case 'bottom-left': - moveX = 0; - moveY = dims.height; - break; - case 'bottom-right': - moveX = dims.width; - moveY = dims.height; - break; - case 'center': - moveX = dims.width / 2; - moveY = dims.height / 2; - break; - } - - return new Effect.Parallel( - [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), - new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), - new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) - ], Object.extend({ - beforeStartInternal: function(effect) { - effect.effects[0].element.makePositioned(); - effect.effects[0].element.makeClipping(); }, - afterFinishInternal: function(effect) { - effect.effects[0].element.hide(); - effect.effects[0].element.undoClipping(); - effect.effects[0].element.undoPositioned(); - effect.effects[0].element.setStyle(oldStyle); } - }, options) - ); -} - -Effect.Pulsate = function(element) { - element = $(element); - var options = arguments[1] || {}; - var oldOpacity = element.getInlineOpacity(); - var transition = options.transition || Effect.Transitions.sinoidal; - var reverser = function(pos){ return transition(1-Effect.Transitions.pulse(pos)) }; - reverser.bind(transition); - return new Effect.Opacity(element, - Object.extend(Object.extend({ duration: 3.0, from: 0, - afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } - }, options), {transition: reverser})); -} - -Effect.Fold = function(element) { - element = $(element); - var oldStyle = { - top: element.style.top, - left: element.style.left, - width: element.style.width, - height: element.style.height }; - Element.makeClipping(element); - return new Effect.Scale(element, 5, Object.extend({ - scaleContent: false, - scaleX: false, - afterFinishInternal: function(effect) { - new Effect.Scale(element, 1, { - scaleContent: false, - scaleY: false, - afterFinishInternal: function(effect) { - effect.element.hide(); - effect.element.undoClipping(); - effect.element.setStyle(oldStyle); - } }); - }}, arguments[1] || {})); -}; - -['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom', - 'collectTextNodes','collectTextNodesIgnoreClass','childrenWithClassName'].each( - function(f) { Element.Methods[f] = Element[f]; } -); - -Element.Methods.visualEffect = function(element, effect, options) { - s = effect.gsub(/_/, '-').camelize(); - effect_class = s.charAt(0).toUpperCase() + s.substring(1); - new Effect[effect_class](element, options); - return $(element); -}; - -Element.addMethods(); \ No newline at end of file diff --git a/library/cropper/lib/prototype.js b/library/cropper/lib/prototype.js deleted file mode 100644 index 0caf9cd7f..000000000 --- a/library/cropper/lib/prototype.js +++ /dev/null @@ -1,2006 +0,0 @@ -/* Prototype JavaScript framework, version 1.5.0_rc0 - * (c) 2005 Sam Stephenson - * - * Prototype is freely distributable under the terms of an MIT-style license. - * For details, see the Prototype web site: http://prototype.conio.net/ - * -/*--------------------------------------------------------------------------*/ - -var Prototype = { - Version: '1.5.0_rc0', - ScriptFragment: '(?:)((\n|\r|.)*?)(?:<\/script>)', - - emptyFunction: function() {}, - K: function(x) {return x} -} - -var Class = { - create: function() { - return function() { - this.initialize.apply(this, arguments); - } - } -} - -var Abstract = new Object(); - -Object.extend = function(destination, source) { - for (var property in source) { - destination[property] = source[property]; - } - return destination; -} - -Object.inspect = function(object) { - try { - if (object == undefined) return 'undefined'; - if (object == null) return 'null'; - return object.inspect ? object.inspect() : object.toString(); - } catch (e) { - if (e instanceof RangeError) return '...'; - throw e; - } -} - -Function.prototype.bind = function() { - var __method = this, args = $A(arguments), object = args.shift(); - return function() { - return __method.apply(object, args.concat($A(arguments))); - } -} - -Function.prototype.bindAsEventListener = function(object) { - var __method = this; - return function(event) { - return __method.call(object, event || window.event); - } -} - -Object.extend(Number.prototype, { - toColorPart: function() { - var digits = this.toString(16); - if (this < 16) return '0' + digits; - return digits; - }, - - succ: function() { - return this + 1; - }, - - times: function(iterator) { - $R(0, this, true).each(iterator); - return this; - } -}); - -var Try = { - these: function() { - var returnValue; - - for (var i = 0; i < arguments.length; i++) { - var lambda = arguments[i]; - try { - returnValue = lambda(); - break; - } catch (e) {} - } - - return returnValue; - } -} - -/*--------------------------------------------------------------------------*/ - -var PeriodicalExecuter = Class.create(); -PeriodicalExecuter.prototype = { - initialize: function(callback, frequency) { - this.callback = callback; - this.frequency = frequency; - this.currentlyExecuting = false; - - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - if (!this.currentlyExecuting) { - try { - this.currentlyExecuting = true; - this.callback(); - } finally { - this.currentlyExecuting = false; - } - } - } -} -Object.extend(String.prototype, { - gsub: function(pattern, replacement) { - var result = '', source = this, match; - replacement = arguments.callee.prepareReplacement(replacement); - - while (source.length > 0) { - if (match = source.match(pattern)) { - result += source.slice(0, match.index); - result += (replacement(match) || '').toString(); - source = source.slice(match.index + match[0].length); - } else { - result += source, source = ''; - } - } - return result; - }, - - sub: function(pattern, replacement, count) { - replacement = this.gsub.prepareReplacement(replacement); - count = count === undefined ? 1 : count; - - return this.gsub(pattern, function(match) { - if (--count < 0) return match[0]; - return replacement(match); - }); - }, - - scan: function(pattern, iterator) { - this.gsub(pattern, iterator); - return this; - }, - - truncate: function(length, truncation) { - length = length || 30; - truncation = truncation === undefined ? '...' : truncation; - return this.length > length ? - this.slice(0, length - truncation.length) + truncation : this; - }, - - strip: function() { - return this.replace(/^\s+/, '').replace(/\s+$/, ''); - }, - - stripTags: function() { - return this.replace(/<\/?[^>]+>/gi, ''); - }, - - stripScripts: function() { - return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); - }, - - extractScripts: function() { - var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); - var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); - return (this.match(matchAll) || []).map(function(scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }); - }, - - evalScripts: function() { - return this.extractScripts().map(function(script) { return eval(script) }); - }, - - escapeHTML: function() { - var div = document.createElement('div'); - var text = document.createTextNode(this); - div.appendChild(text); - return div.innerHTML; - }, - - unescapeHTML: function() { - var div = document.createElement('div'); - div.innerHTML = this.stripTags(); - return div.childNodes[0] ? div.childNodes[0].nodeValue : ''; - }, - - toQueryParams: function() { - var pairs = this.match(/^\??(.*)$/)[1].split('&'); - return pairs.inject({}, function(params, pairString) { - var pair = pairString.split('='); - params[pair[0]] = pair[1]; - return params; - }); - }, - - toArray: function() { - return this.split(''); - }, - - camelize: function() { - var oStringList = this.split('-'); - if (oStringList.length == 1) return oStringList[0]; - - var camelizedString = this.indexOf('-') == 0 - ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1) - : oStringList[0]; - - for (var i = 1, len = oStringList.length; i < len; i++) { - var s = oStringList[i]; - camelizedString += s.charAt(0).toUpperCase() + s.substring(1); - } - - return camelizedString; - }, - - inspect: function() { - return "'" + this.replace(/\\/g, '\\\\').replace(/'/g, '\\\'') + "'"; - } -}); - -String.prototype.gsub.prepareReplacement = function(replacement) { - if (typeof replacement == 'function') return replacement; - var template = new Template(replacement); - return function(match) { return template.evaluate(match) }; -} - -String.prototype.parseQuery = String.prototype.toQueryParams; - -var Template = Class.create(); -Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; -Template.prototype = { - initialize: function(template, pattern) { - this.template = template.toString(); - this.pattern = pattern || Template.Pattern; - }, - - evaluate: function(object) { - return this.template.gsub(this.pattern, function(match) { - var before = match[1]; - if (before == '\\') return match[2]; - return before + (object[match[3]] || '').toString(); - }); - } -} - -var $break = new Object(); -var $continue = new Object(); - -var Enumerable = { - each: function(iterator) { - var index = 0; - try { - this._each(function(value) { - try { - iterator(value, index++); - } catch (e) { - if (e != $continue) throw e; - } - }); - } catch (e) { - if (e != $break) throw e; - } - }, - - all: function(iterator) { - var result = true; - this.each(function(value, index) { - result = result && !!(iterator || Prototype.K)(value, index); - if (!result) throw $break; - }); - return result; - }, - - any: function(iterator) { - var result = true; - this.each(function(value, index) { - if (result = !!(iterator || Prototype.K)(value, index)) - throw $break; - }); - return result; - }, - - collect: function(iterator) { - var results = []; - this.each(function(value, index) { - results.push(iterator(value, index)); - }); - return results; - }, - - detect: function (iterator) { - var result; - this.each(function(value, index) { - if (iterator(value, index)) { - result = value; - throw $break; - } - }); - return result; - }, - - findAll: function(iterator) { - var results = []; - this.each(function(value, index) { - if (iterator(value, index)) - results.push(value); - }); - return results; - }, - - grep: function(pattern, iterator) { - var results = []; - this.each(function(value, index) { - var stringValue = value.toString(); - if (stringValue.match(pattern)) - results.push((iterator || Prototype.K)(value, index)); - }) - return results; - }, - - include: function(object) { - var found = false; - this.each(function(value) { - if (value == object) { - found = true; - throw $break; - } - }); - return found; - }, - - inject: function(memo, iterator) { - this.each(function(value, index) { - memo = iterator(memo, value, index); - }); - return memo; - }, - - invoke: function(method) { - var args = $A(arguments).slice(1); - return this.collect(function(value) { - return value[method].apply(value, args); - }); - }, - - max: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (result == undefined || value >= result) - result = value; - }); - return result; - }, - - min: function(iterator) { - var result; - this.each(function(value, index) { - value = (iterator || Prototype.K)(value, index); - if (result == undefined || value < result) - result = value; - }); - return result; - }, - - partition: function(iterator) { - var trues = [], falses = []; - this.each(function(value, index) { - ((iterator || Prototype.K)(value, index) ? - trues : falses).push(value); - }); - return [trues, falses]; - }, - - pluck: function(property) { - var results = []; - this.each(function(value, index) { - results.push(value[property]); - }); - return results; - }, - - reject: function(iterator) { - var results = []; - this.each(function(value, index) { - if (!iterator(value, index)) - results.push(value); - }); - return results; - }, - - sortBy: function(iterator) { - return this.collect(function(value, index) { - return {value: value, criteria: iterator(value, index)}; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - return a < b ? -1 : a > b ? 1 : 0; - }).pluck('value'); - }, - - toArray: function() { - return this.collect(Prototype.K); - }, - - zip: function() { - var iterator = Prototype.K, args = $A(arguments); - if (typeof args.last() == 'function') - iterator = args.pop(); - - var collections = [this].concat(args).map($A); - return this.map(function(value, index) { - return iterator(collections.pluck(index)); - }); - }, - - inspect: function() { - return '#'; - } -} - -Object.extend(Enumerable, { - map: Enumerable.collect, - find: Enumerable.detect, - select: Enumerable.findAll, - member: Enumerable.include, - entries: Enumerable.toArray -}); -var $A = Array.from = function(iterable) { - if (!iterable) return []; - if (iterable.toArray) { - return iterable.toArray(); - } else { - var results = []; - for (var i = 0; i < iterable.length; i++) - results.push(iterable[i]); - return results; - } -} - -Object.extend(Array.prototype, Enumerable); - -if (!Array.prototype._reverse) - Array.prototype._reverse = Array.prototype.reverse; - -Object.extend(Array.prototype, { - _each: function(iterator) { - for (var i = 0; i < this.length; i++) - iterator(this[i]); - }, - - clear: function() { - this.length = 0; - return this; - }, - - first: function() { - return this[0]; - }, - - last: function() { - return this[this.length - 1]; - }, - - compact: function() { - return this.select(function(value) { - return value != undefined || value != null; - }); - }, - - flatten: function() { - return this.inject([], function(array, value) { - return array.concat(value && value.constructor == Array ? - value.flatten() : [value]); - }); - }, - - without: function() { - var values = $A(arguments); - return this.select(function(value) { - return !values.include(value); - }); - }, - - indexOf: function(object) { - for (var i = 0; i < this.length; i++) - if (this[i] == object) return i; - return -1; - }, - - reverse: function(inline) { - return (inline !== false ? this : this.toArray())._reverse(); - }, - - inspect: function() { - return '[' + this.map(Object.inspect).join(', ') + ']'; - } -}); -var Hash = { - _each: function(iterator) { - for (var key in this) { - var value = this[key]; - if (typeof value == 'function') continue; - - var pair = [key, value]; - pair.key = key; - pair.value = value; - iterator(pair); - } - }, - - keys: function() { - return this.pluck('key'); - }, - - values: function() { - return this.pluck('value'); - }, - - merge: function(hash) { - return $H(hash).inject($H(this), function(mergedHash, pair) { - mergedHash[pair.key] = pair.value; - return mergedHash; - }); - }, - - toQueryString: function() { - return this.map(function(pair) { - return pair.map(encodeURIComponent).join('='); - }).join('&'); - }, - - inspect: function() { - return '#'; - } -} - -function $H(object) { - var hash = Object.extend({}, object || {}); - Object.extend(hash, Enumerable); - Object.extend(hash, Hash); - return hash; -} -ObjectRange = Class.create(); -Object.extend(ObjectRange.prototype, Enumerable); -Object.extend(ObjectRange.prototype, { - initialize: function(start, end, exclusive) { - this.start = start; - this.end = end; - this.exclusive = exclusive; - }, - - _each: function(iterator) { - var value = this.start; - do { - iterator(value); - value = value.succ(); - } while (this.include(value)); - }, - - include: function(value) { - if (value < this.start) - return false; - if (this.exclusive) - return value < this.end; - return value <= this.end; - } -}); - -var $R = function(start, end, exclusive) { - return new ObjectRange(start, end, exclusive); -} - -var Ajax = { - getTransport: function() { - return Try.these( - function() {return new XMLHttpRequest()}, - function() {return new ActiveXObject('Msxml2.XMLHTTP')}, - function() {return new ActiveXObject('Microsoft.XMLHTTP')} - ) || false; - }, - - activeRequestCount: 0 -} - -Ajax.Responders = { - responders: [], - - _each: function(iterator) { - this.responders._each(iterator); - }, - - register: function(responderToAdd) { - if (!this.include(responderToAdd)) - this.responders.push(responderToAdd); - }, - - unregister: function(responderToRemove) { - this.responders = this.responders.without(responderToRemove); - }, - - dispatch: function(callback, request, transport, json) { - this.each(function(responder) { - if (responder[callback] && typeof responder[callback] == 'function') { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} - } - }); - } -}; - -Object.extend(Ajax.Responders, Enumerable); - -Ajax.Responders.register({ - onCreate: function() { - Ajax.activeRequestCount++; - }, - - onComplete: function() { - Ajax.activeRequestCount--; - } -}); - -Ajax.Base = function() {}; -Ajax.Base.prototype = { - setOptions: function(options) { - this.options = { - method: 'post', - asynchronous: true, - contentType: 'application/x-www-form-urlencoded', - parameters: '' - } - Object.extend(this.options, options || {}); - }, - - responseIsSuccess: function() { - return this.transport.status == undefined - || this.transport.status == 0 - || (this.transport.status >= 200 && this.transport.status < 300); - }, - - responseIsFailure: function() { - return !this.responseIsSuccess(); - } -} - -Ajax.Request = Class.create(); -Ajax.Request.Events = - ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; - -Ajax.Request.prototype = Object.extend(new Ajax.Base(), { - initialize: function(url, options) { - this.transport = Ajax.getTransport(); - this.setOptions(options); - this.request(url); - }, - - request: function(url) { - var parameters = this.options.parameters || ''; - if (parameters.length > 0) parameters += '&_='; - - try { - this.url = url; - if (this.options.method == 'get' && parameters.length > 0) - this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; - - Ajax.Responders.dispatch('onCreate', this, this.transport); - - this.transport.open(this.options.method, this.url, - this.options.asynchronous); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = this.onStateChange.bind(this); - setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10); - } - - this.setRequestHeaders(); - - var body = this.options.postBody ? this.options.postBody : parameters; - this.transport.send(this.options.method == 'post' ? body : null); - - } catch (e) { - this.dispatchException(e); - } - }, - - setRequestHeaders: function() { - var requestHeaders = - ['X-Requested-With', 'XMLHttpRequest', - 'X-Prototype-Version', Prototype.Version, - 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*']; - - if (this.options.method == 'post') { - requestHeaders.push('Content-type', this.options.contentType); - - /* Force "Connection: close" for Mozilla browsers to work around - * a bug where XMLHttpReqeuest sends an incorrect Content-length - * header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType) - requestHeaders.push('Connection', 'close'); - } - - if (this.options.requestHeaders) - requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); - - for (var i = 0; i < requestHeaders.length; i += 2) - this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); - }, - - onStateChange: function() { - var readyState = this.transport.readyState; - if (readyState != 1) - this.respondToReadyState(this.transport.readyState); - }, - - header: function(name) { - try { - return this.transport.getResponseHeader(name); - } catch (e) {} - }, - - evalJSON: function() { - try { - return eval('(' + this.header('X-JSON') + ')'); - } catch (e) {} - }, - - evalResponse: function() { - try { - return eval(this.transport.responseText); - } catch (e) { - this.dispatchException(e); - } - }, - - respondToReadyState: function(readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - if (event == 'Complete') { - try { - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || Prototype.emptyFunction)(transport, json); - } catch (e) { - this.dispatchException(e); - } - - if ((this.header('Content-type') || '').match(/^text\/javascript/i)) - this.evalResponse(); - } - - try { - (this.options['on' + event] || Prototype.emptyFunction)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - } catch (e) { - this.dispatchException(e); - } - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') - this.transport.onreadystatechange = Prototype.emptyFunction; - }, - - dispatchException: function(exception) { - (this.options.onException || Prototype.emptyFunction)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -Ajax.Updater = Class.create(); - -Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), { - initialize: function(container, url, options) { - this.containers = { - success: container.success ? $(container.success) : $(container), - failure: container.failure ? $(container.failure) : - (container.success ? null : $(container)) - } - - this.transport = Ajax.getTransport(); - this.setOptions(options); - - var onComplete = this.options.onComplete || Prototype.emptyFunction; - this.options.onComplete = (function(transport, object) { - this.updateContent(); - onComplete(transport, object); - }).bind(this); - - this.request(url); - }, - - updateContent: function() { - var receiver = this.responseIsSuccess() ? - this.containers.success : this.containers.failure; - var response = this.transport.responseText; - - if (!this.options.evalScripts) - response = response.stripScripts(); - - if (receiver) { - if (this.options.insertion) { - new this.options.insertion(receiver, response); - } else { - Element.update(receiver, response); - } - } - - if (this.responseIsSuccess()) { - if (this.onComplete) - setTimeout(this.onComplete.bind(this), 10); - } - } -}); - -Ajax.PeriodicalUpdater = Class.create(); -Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), { - initialize: function(container, url, options) { - this.setOptions(options); - this.onComplete = this.options.onComplete; - - this.frequency = (this.options.frequency || 2); - this.decay = (this.options.decay || 1); - - this.updater = {}; - this.container = container; - this.url = url; - - this.start(); - }, - - start: function() { - this.options.onComplete = this.updateComplete.bind(this); - this.onTimerEvent(); - }, - - stop: function() { - this.updater.onComplete = undefined; - clearTimeout(this.timer); - (this.onComplete || Prototype.emptyFunction).apply(this, arguments); - }, - - updateComplete: function(request) { - if (this.options.decay) { - this.decay = (request.responseText == this.lastText ? - this.decay * this.options.decay : 1); - - this.lastText = request.responseText; - } - this.timer = setTimeout(this.onTimerEvent.bind(this), - this.decay * this.frequency * 1000); - }, - - onTimerEvent: function() { - this.updater = new Ajax.Updater(this.container, this.url, this.options); - } -}); -function $() { - var results = [], element; - for (var i = 0; i < arguments.length; i++) { - element = arguments[i]; - if (typeof element == 'string') - element = document.getElementById(element); - results.push(Element.extend(element)); - } - return results.length < 2 ? results[0] : results; -} - -document.getElementsByClassName = function(className, parentElement) { - var children = ($(parentElement) || document.body).getElementsByTagName('*'); - return $A(children).inject([], function(elements, child) { - if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)"))) - elements.push(Element.extend(child)); - return elements; - }); -} - -/*--------------------------------------------------------------------------*/ - -if (!window.Element) - var Element = new Object(); - -Element.extend = function(element) { - if (!element) return; - if (_nativeExtensions) return element; - - if (!element._extended && element.tagName && element != window) { - var methods = Element.Methods, cache = Element.extend.cache; - for (property in methods) { - var value = methods[property]; - if (typeof value == 'function') - element[property] = cache.findOrStore(value); - } - } - - element._extended = true; - return element; -} - -Element.extend.cache = { - findOrStore: function(value) { - return this[value] = this[value] || function() { - return value.apply(null, [this].concat($A(arguments))); - } - } -} - -Element.Methods = { - visible: function(element) { - return $(element).style.display != 'none'; - }, - - toggle: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - Element[Element.visible(element) ? 'hide' : 'show'](element); - } - }, - - hide: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = 'none'; - } - }, - - show: function() { - for (var i = 0; i < arguments.length; i++) { - var element = $(arguments[i]); - element.style.display = ''; - } - }, - - remove: function(element) { - element = $(element); - element.parentNode.removeChild(element); - }, - - update: function(element, html) { - $(element).innerHTML = html.stripScripts(); - setTimeout(function() {html.evalScripts()}, 10); - }, - - replace: function(element, html) { - element = $(element); - if (element.outerHTML) { - element.outerHTML = html.stripScripts(); - } else { - var range = element.ownerDocument.createRange(); - range.selectNodeContents(element); - element.parentNode.replaceChild( - range.createContextualFragment(html.stripScripts()), element); - } - setTimeout(function() {html.evalScripts()}, 10); - }, - - getHeight: function(element) { - element = $(element); - return element.offsetHeight; - }, - - classNames: function(element) { - return new Element.ClassNames(element); - }, - - hasClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).include(className); - }, - - addClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).add(className); - }, - - removeClassName: function(element, className) { - if (!(element = $(element))) return; - return Element.classNames(element).remove(className); - }, - - // removes whitespace-only text node children - cleanWhitespace: function(element) { - element = $(element); - for (var i = 0; i < element.childNodes.length; i++) { - var node = element.childNodes[i]; - if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) - Element.remove(node); - } - }, - - empty: function(element) { - return $(element).innerHTML.match(/^\s*$/); - }, - - childOf: function(element, ancestor) { - element = $(element), ancestor = $(ancestor); - while (element = element.parentNode) - if (element == ancestor) return true; - return false; - }, - - scrollTo: function(element) { - element = $(element); - var x = element.x ? element.x : element.offsetLeft, - y = element.y ? element.y : element.offsetTop; - window.scrollTo(x, y); - }, - - getStyle: function(element, style) { - element = $(element); - var value = element.style[style.camelize()]; - if (!value) { - if (document.defaultView && document.defaultView.getComputedStyle) { - var css = document.defaultView.getComputedStyle(element, null); - value = css ? css.getPropertyValue(style) : null; - } else if (element.currentStyle) { - value = element.currentStyle[style.camelize()]; - } - } - - if (window.opera && ['left', 'top', 'right', 'bottom'].include(style)) - if (Element.getStyle(element, 'position') == 'static') value = 'auto'; - - return value == 'auto' ? null : value; - }, - - setStyle: function(element, style) { - element = $(element); - for (var name in style) - element.style[name.camelize()] = style[name]; - }, - - getDimensions: function(element) { - element = $(element); - if (Element.getStyle(element, 'display') != 'none') - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = ''; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = 'none'; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - - makePositioned: function(element) { - element = $(element); - var pos = Element.getStyle(element, 'position'); - if (pos == 'static' || !pos) { - element._madePositioned = true; - element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined - if (window.opera) { - element.style.top = 0; - element.style.left = 0; - } - } - }, - - undoPositioned: function(element) { - element = $(element); - if (element._madePositioned) { - element._madePositioned = undefined; - element.style.position = - element.style.top = - element.style.left = - element.style.bottom = - element.style.right = ''; - } - }, - - makeClipping: function(element) { - element = $(element); - if (element._overflow) return; - element._overflow = element.style.overflow; - if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden') - element.style.overflow = 'hidden'; - }, - - undoClipping: function(element) { - element = $(element); - if (element._overflow) return; - element.style.overflow = element._overflow; - element._overflow = undefined; - } -} - -Object.extend(Element, Element.Methods); - -var _nativeExtensions = false; - -if(!HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - var HTMLElement = {} - HTMLElement.prototype = document.createElement('div').__proto__; -} - -Element.addMethods = function(methods) { - Object.extend(Element.Methods, methods || {}); - - if(typeof HTMLElement != 'undefined') { - var methods = Element.Methods, cache = Element.extend.cache; - for (property in methods) { - var value = methods[property]; - if (typeof value == 'function') - HTMLElement.prototype[property] = cache.findOrStore(value); - } - _nativeExtensions = true; - } -} - -Element.addMethods(); - -var Toggle = new Object(); -Toggle.display = Element.toggle; - -/*--------------------------------------------------------------------------*/ - -Abstract.Insertion = function(adjacency) { - this.adjacency = adjacency; -} - -Abstract.Insertion.prototype = { - initialize: function(element, content) { - this.element = $(element); - this.content = content.stripScripts(); - - if (this.adjacency && this.element.insertAdjacentHTML) { - try { - this.element.insertAdjacentHTML(this.adjacency, this.content); - } catch (e) { - var tagName = this.element.tagName.toLowerCase(); - if (tagName == 'tbody' || tagName == 'tr') { - this.insertContent(this.contentFromAnonymousTable()); - } else { - throw e; - } - } - } else { - this.range = this.element.ownerDocument.createRange(); - if (this.initializeRange) this.initializeRange(); - this.insertContent([this.range.createContextualFragment(this.content)]); - } - - setTimeout(function() {content.evalScripts()}, 10); - }, - - contentFromAnonymousTable: function() { - var div = document.createElement('div'); - div.innerHTML = '

    {{$k}}{{$v}}
    ' + this.content + '
    '; - return $A(div.childNodes[0].childNodes[0].childNodes); - } -} - -var Insertion = new Object(); - -Insertion.Before = Class.create(); -Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), { - initializeRange: function() { - this.range.setStartBefore(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, this.element); - }).bind(this)); - } -}); - -Insertion.Top = Class.create(); -Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(true); - }, - - insertContent: function(fragments) { - fragments.reverse(false).each((function(fragment) { - this.element.insertBefore(fragment, this.element.firstChild); - }).bind(this)); - } -}); - -Insertion.Bottom = Class.create(); -Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), { - initializeRange: function() { - this.range.selectNodeContents(this.element); - this.range.collapse(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.appendChild(fragment); - }).bind(this)); - } -}); - -Insertion.After = Class.create(); -Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), { - initializeRange: function() { - this.range.setStartAfter(this.element); - }, - - insertContent: function(fragments) { - fragments.each((function(fragment) { - this.element.parentNode.insertBefore(fragment, - this.element.nextSibling); - }).bind(this)); - } -}); - -/*--------------------------------------------------------------------------*/ - -Element.ClassNames = Class.create(); -Element.ClassNames.prototype = { - initialize: function(element) { - this.element = $(element); - }, - - _each: function(iterator) { - this.element.className.split(/\s+/).select(function(name) { - return name.length > 0; - })._each(iterator); - }, - - set: function(className) { - this.element.className = className; - }, - - add: function(classNameToAdd) { - if (this.include(classNameToAdd)) return; - this.set(this.toArray().concat(classNameToAdd).join(' ')); - }, - - remove: function(classNameToRemove) { - if (!this.include(classNameToRemove)) return; - this.set(this.select(function(className) { - return className != classNameToRemove; - }).join(' ')); - }, - - toString: function() { - return this.toArray().join(' '); - } -} - -Object.extend(Element.ClassNames.prototype, Enumerable); -var Selector = Class.create(); -Selector.prototype = { - initialize: function(expression) { - this.params = {classNames: []}; - this.expression = expression.toString().strip(); - this.parseExpression(); - this.compileMatcher(); - }, - - parseExpression: function() { - function abort(message) { throw 'Parse error in selector: ' + message; } - - if (this.expression == '') abort('empty expression'); - - var params = this.params, expr = this.expression, match, modifier, clause, rest; - while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) { - params.attributes = params.attributes || []; - params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''}); - expr = match[1]; - } - - if (expr == '*') return this.params.wildcard = true; - - while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) { - modifier = match[1], clause = match[2], rest = match[3]; - switch (modifier) { - case '#': params.id = clause; break; - case '.': params.classNames.push(clause); break; - case '': - case undefined: params.tagName = clause.toUpperCase(); break; - default: abort(expr.inspect()); - } - expr = rest; - } - - if (expr.length > 0) abort(expr.inspect()); - }, - - buildMatchExpression: function() { - var params = this.params, conditions = [], clause; - - if (params.wildcard) - conditions.push('true'); - if (clause = params.id) - conditions.push('element.id == ' + clause.inspect()); - if (clause = params.tagName) - conditions.push('element.tagName.toUpperCase() == ' + clause.inspect()); - if ((clause = params.classNames).length > 0) - for (var i = 0; i < clause.length; i++) - conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')'); - if (clause = params.attributes) { - clause.each(function(attribute) { - var value = 'element.getAttribute(' + attribute.name.inspect() + ')'; - var splitValueBy = function(delimiter) { - return value + ' && ' + value + '.split(' + delimiter.inspect() + ')'; - } - - switch (attribute.operator) { - case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break; - case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break; - case '|=': conditions.push( - splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect() - ); break; - case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break; - case '': - case undefined: conditions.push(value + ' != null'); break; - default: throw 'Unknown operator ' + attribute.operator + ' in selector'; - } - }); - } - - return conditions.join(' && '); - }, - - compileMatcher: function() { - this.match = new Function('element', 'if (!element.tagName) return false; \ - return ' + this.buildMatchExpression()); - }, - - findElements: function(scope) { - var element; - - if (element = $(this.params.id)) - if (this.match(element)) - if (!scope || Element.childOf(element, scope)) - return [element]; - - scope = (scope || document).getElementsByTagName(this.params.tagName || '*'); - - var results = []; - for (var i = 0; i < scope.length; i++) - if (this.match(element = scope[i])) - results.push(Element.extend(element)); - - return results; - }, - - toString: function() { - return this.expression; - } -} - -function $$() { - return $A(arguments).map(function(expression) { - return expression.strip().split(/\s+/).inject([null], function(results, expr) { - var selector = new Selector(expr); - return results.map(selector.findElements.bind(selector)).flatten(); - }); - }).flatten(); -} -var Field = { - clear: function() { - for (var i = 0; i < arguments.length; i++) - $(arguments[i]).value = ''; - }, - - focus: function(element) { - $(element).focus(); - }, - - present: function() { - for (var i = 0; i < arguments.length; i++) - if ($(arguments[i]).value == '') return false; - return true; - }, - - select: function(element) { - $(element).select(); - }, - - activate: function(element) { - element = $(element); - element.focus(); - if (element.select) - element.select(); - } -} - -/*--------------------------------------------------------------------------*/ - -var Form = { - serialize: function(form) { - var elements = Form.getElements($(form)); - var queryComponents = new Array(); - - for (var i = 0; i < elements.length; i++) { - var queryComponent = Form.Element.serialize(elements[i]); - if (queryComponent) - queryComponents.push(queryComponent); - } - - return queryComponents.join('&'); - }, - - getElements: function(form) { - form = $(form); - var elements = new Array(); - - for (var tagName in Form.Element.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) - elements.push(tagElements[j]); - } - return elements; - }, - - getInputs: function(form, typeName, name) { - form = $(form); - var inputs = form.getElementsByTagName('input'); - - if (!typeName && !name) - return inputs; - - var matchingInputs = new Array(); - for (var i = 0; i < inputs.length; i++) { - var input = inputs[i]; - if ((typeName && input.type != typeName) || - (name && input.name != name)) - continue; - matchingInputs.push(input); - } - - return matchingInputs; - }, - - disable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.blur(); - element.disabled = 'true'; - } - }, - - enable: function(form) { - var elements = Form.getElements(form); - for (var i = 0; i < elements.length; i++) { - var element = elements[i]; - element.disabled = ''; - } - }, - - findFirstElement: function(form) { - return Form.getElements(form).find(function(element) { - return element.type != 'hidden' && !element.disabled && - ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); - }); - }, - - focusFirstElement: function(form) { - Field.activate(Form.findFirstElement(form)); - }, - - reset: function(form) { - $(form).reset(); - } -} - -Form.Element = { - serialize: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) { - var key = encodeURIComponent(parameter[0]); - if (key.length == 0) return; - - if (parameter[1].constructor != Array) - parameter[1] = [parameter[1]]; - - return parameter[1].map(function(value) { - return key + '=' + encodeURIComponent(value); - }).join('&'); - } - }, - - getValue: function(element) { - element = $(element); - var method = element.tagName.toLowerCase(); - var parameter = Form.Element.Serializers[method](element); - - if (parameter) - return parameter[1]; - } -} - -Form.Element.Serializers = { - input: function(element) { - switch (element.type.toLowerCase()) { - case 'submit': - case 'hidden': - case 'password': - case 'text': - return Form.Element.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return Form.Element.Serializers.inputSelector(element); - } - return false; - }, - - inputSelector: function(element) { - if (element.checked) - return [element.name, element.value]; - }, - - textarea: function(element) { - return [element.name, element.value]; - }, - - select: function(element) { - return Form.Element.Serializers[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - }, - - selectOne: function(element) { - var value = '', opt, index = element.selectedIndex; - if (index >= 0) { - opt = element.options[index]; - value = opt.value || opt.text; - } - return [element.name, value]; - }, - - selectMany: function(element) { - var value = []; - for (var i = 0; i < element.length; i++) { - var opt = element.options[i]; - if (opt.selected) - value.push(opt.value || opt.text); - } - return [element.name, value]; - } -} - -/*--------------------------------------------------------------------------*/ - -var $F = Form.Element.getValue; - -/*--------------------------------------------------------------------------*/ - -Abstract.TimedObserver = function() {} -Abstract.TimedObserver.prototype = { - initialize: function(element, frequency, callback) { - this.frequency = frequency; - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - this.registerCallback(); - }, - - registerCallback: function() { - setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); - }, - - onTimerEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - } -} - -Form.Element.Observer = Class.create(); -Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.Observer = Class.create(); -Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); - -/*--------------------------------------------------------------------------*/ - -Abstract.EventObserver = function() {} -Abstract.EventObserver.prototype = { - initialize: function(element, callback) { - this.element = $(element); - this.callback = callback; - - this.lastValue = this.getValue(); - if (this.element.tagName.toLowerCase() == 'form') - this.registerFormCallbacks(); - else - this.registerCallback(this.element); - }, - - onElementEvent: function() { - var value = this.getValue(); - if (this.lastValue != value) { - this.callback(this.element, value); - this.lastValue = value; - } - }, - - registerFormCallbacks: function() { - var elements = Form.getElements(this.element); - for (var i = 0; i < elements.length; i++) - this.registerCallback(elements[i]); - }, - - registerCallback: function(element) { - if (element.type) { - switch (element.type.toLowerCase()) { - case 'checkbox': - case 'radio': - Event.observe(element, 'click', this.onElementEvent.bind(this)); - break; - case 'password': - case 'text': - case 'textarea': - case 'select-one': - case 'select-multiple': - Event.observe(element, 'change', this.onElementEvent.bind(this)); - break; - } - } - } -} - -Form.Element.EventObserver = Class.create(); -Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.Element.getValue(this.element); - } -}); - -Form.EventObserver = Class.create(); -Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), { - getValue: function() { - return Form.serialize(this.element); - } -}); -if (!window.Event) { - var Event = new Object(); -} - -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - - element: function(event) { - return event.target || event.srcElement; - }, - - isLeftClick: function(event) { - return (((event.which) && (event.which == 1)) || - ((event.button) && (event.button == 1))); - }, - - pointerX: function(event) { - return event.pageX || (event.clientX + - (document.documentElement.scrollLeft || document.body.scrollLeft)); - }, - - pointerY: function(event) { - return event.pageY || (event.clientY + - (document.documentElement.scrollTop || document.body.scrollTop)); - }, - - stop: function(event) { - if (event.preventDefault) { - event.preventDefault(); - event.stopPropagation(); - } else { - event.returnValue = false; - event.cancelBubble = true; - } - }, - - // find the first node with the given tagName, starting from the - // node the event was triggered on; traverses the DOM upwards - findElement: function(event, tagName) { - var element = Event.element(event); - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))) - element = element.parentNode; - return element; - }, - - observers: false, - - _observeAndCache: function(element, name, observer, useCapture) { - if (!this.observers) this.observers = []; - if (element.addEventListener) { - this.observers.push([element, name, observer, useCapture]); - element.addEventListener(name, observer, useCapture); - } else if (element.attachEvent) { - this.observers.push([element, name, observer, useCapture]); - element.attachEvent('on' + name, observer); - } - }, - - unloadCache: function() { - if (!Event.observers) return; - for (var i = 0; i < Event.observers.length; i++) { - Event.stopObserving.apply(this, Event.observers[i]); - Event.observers[i][0] = null; - } - Event.observers = false; - }, - - observe: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.attachEvent)) - name = 'keydown'; - - this._observeAndCache(element, name, observer, useCapture); - }, - - stopObserving: function(element, name, observer, useCapture) { - var element = $(element); - useCapture = useCapture || false; - - if (name == 'keypress' && - (navigator.appVersion.match(/Konqueror|Safari|KHTML/) - || element.detachEvent)) - name = 'keydown'; - - if (element.removeEventListener) { - element.removeEventListener(name, observer, useCapture); - } else if (element.detachEvent) { - element.detachEvent('on' + name, observer); - } - } -}); - -/* prevent memory leaks in IE */ -if (navigator.appVersion.match(/\bMSIE\b/)) - Event.observe(window, 'unload', Event.unloadCache, false); -var Position = { - // set to true if needed, warning: firefox performance problems - // NOT neeeded for page scrolling, only if draggable contained in - // scrollable elements - includeScrollOffsets: false, - - // must be called before calling withinIncludingScrolloffset, every time the - // page is scrolled - prepare: function() { - this.deltaX = window.pageXOffset - || document.documentElement.scrollLeft - || document.body.scrollLeft - || 0; - this.deltaY = window.pageYOffset - || document.documentElement.scrollTop - || document.body.scrollTop - || 0; - }, - - realOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return [valueL, valueT]; - }, - - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return [valueL, valueT]; - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - p = Element.getStyle(element, 'position'); - if (p == 'relative' || p == 'absolute') break; - } - } while (element); - return [valueL, valueT]; - }, - - offsetParent: function(element) { - if (element.offsetParent) return element.offsetParent; - if (element == document.body) return element; - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return element; - - return document.body; - }, - - // caches x/y coordinate pair to use with overlap - within: function(element, x, y) { - if (this.includeScrollOffsets) - return this.withinIncludingScrolloffsets(element, x, y); - this.xcomp = x; - this.ycomp = y; - this.offset = this.cumulativeOffset(element); - - return (y >= this.offset[1] && - y < this.offset[1] + element.offsetHeight && - x >= this.offset[0] && - x < this.offset[0] + element.offsetWidth); - }, - - withinIncludingScrolloffsets: function(element, x, y) { - var offsetcache = this.realOffset(element); - - this.xcomp = x + offsetcache[0] - this.deltaX; - this.ycomp = y + offsetcache[1] - this.deltaY; - this.offset = this.cumulativeOffset(element); - - return (this.ycomp >= this.offset[1] && - this.ycomp < this.offset[1] + element.offsetHeight && - this.xcomp >= this.offset[0] && - this.xcomp < this.offset[0] + element.offsetWidth); - }, - - // within must be called directly before - overlap: function(mode, element) { - if (!mode) return 0; - if (mode == 'vertical') - return ((this.offset[1] + element.offsetHeight) - this.ycomp) / - element.offsetHeight; - if (mode == 'horizontal') - return ((this.offset[0] + element.offsetWidth) - this.xcomp) / - element.offsetWidth; - }, - - clone: function(source, target) { - source = $(source); - target = $(target); - target.style.position = 'absolute'; - var offsets = this.cumulativeOffset(source); - target.style.top = offsets[1] + 'px'; - target.style.left = offsets[0] + 'px'; - target.style.width = source.offsetWidth + 'px'; - target.style.height = source.offsetHeight + 'px'; - }, - - page: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent==document.body) - if (Element.getStyle(element,'position')=='absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } while (element = element.parentNode); - - return [valueL, valueT]; - }, - - clone: function(source, target) { - var options = Object.extend({ - setLeft: true, - setTop: true, - setWidth: true, - setHeight: true, - offsetTop: 0, - offsetLeft: 0 - }, arguments[2] || {}) - - // find page position of source - source = $(source); - var p = Position.page(source); - - // find coordinate system to use - target = $(target); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas - if (Element.getStyle(target,'position') == 'absolute') { - parent = Position.offsetParent(target); - delta = Position.page(parent); - } - - // correct by body offsets (fixes Safari) - if (parent == document.body) { - delta[0] -= document.body.offsetLeft; - delta[1] -= document.body.offsetTop; - } - - // set position - if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; - if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; - if(options.setWidth) target.style.width = source.offsetWidth + 'px'; - if(options.setHeight) target.style.height = source.offsetHeight + 'px'; - }, - - absolutize: function(element) { - element = $(element); - if (element.style.position == 'absolute') return; - Position.prepare(); - - var offsets = Position.positionedOffset(element); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px';; - element.style.left = left + 'px';; - element.style.width = width + 'px';; - element.style.height = height + 'px';; - }, - - relativize: function(element) { - element = $(element); - if (element.style.position == 'relative') return; - Position.prepare(); - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - } -} - -// Safari returns margins on body which is incorrect if the child is absolutely -// positioned. For performance reasons, redefine Position.cumulativeOffset for -// KHTML/WebKit only. -if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) { - Position.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return [valueL, valueT]; - } -} \ No newline at end of file diff --git a/library/cropper/lib/scriptaculous.js b/library/cropper/lib/scriptaculous.js deleted file mode 100644 index f61fc57f7..000000000 --- a/library/cropper/lib/scriptaculous.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// -// 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. - -var Scriptaculous = { - Version: '1.6.1', - require: function(libraryName) { - // inserting via DOM fails in Safari 2.0, so brute force approach - document.write(''); - }, - load: function() { - if((typeof Prototype=='undefined') || - (typeof Element == 'undefined') || - (typeof Element.Methods=='undefined') || - parseFloat(Prototype.Version.split(".")[0] + "." + - Prototype.Version.split(".")[1]) < 1.5) - throw("script.aculo.us requires the Prototype JavaScript framework >= 1.5.0"); - - $A(document.getElementsByTagName("script")).findAll( function(s) { - return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/)) - }).each( function(s) { - var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,''); - var includes = s.src.match(/\?.*load=([a-z,]*)/); - (includes ? includes[1] : 'builder,effects,dragdrop,controls,slider').split(',').each( - function(include) { Scriptaculous.require(path+include+'.js') }); - }); - } -} - -Scriptaculous.load(); \ No newline at end of file diff --git a/library/cropper/lib/slider.js b/library/cropper/lib/slider.js deleted file mode 100644 index c0f1fc01b..000000000 --- a/library/cropper/lib/slider.js +++ /dev/null @@ -1,283 +0,0 @@ -// Copyright (c) 2005 Marty Haught, Thomas Fuchs -// -// See http://script.aculo.us for more info -// -// 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. - -if(!Control) var Control = {}; -Control.Slider = Class.create(); - -// options: -// axis: 'vertical', or 'horizontal' (default) -// -// callbacks: -// onChange(value) -// onSlide(value) -Control.Slider.prototype = { - initialize: function(handle, track, options) { - var slider = this; - - if(handle instanceof Array) { - this.handles = handle.collect( function(e) { return $(e) }); - } else { - this.handles = [$(handle)]; - } - - this.track = $(track); - this.options = options || {}; - - this.axis = this.options.axis || 'horizontal'; - this.increment = this.options.increment || 1; - this.step = parseInt(this.options.step || '1'); - this.range = this.options.range || $R(0,1); - - this.value = 0; // assure backwards compat - this.values = this.handles.map( function() { return 0 }); - this.spans = this.options.spans ? this.options.spans.map(function(s){ return $(s) }) : false; - this.options.startSpan = $(this.options.startSpan || null); - this.options.endSpan = $(this.options.endSpan || null); - - this.restricted = this.options.restricted || false; - - this.maximum = this.options.maximum || this.range.end; - this.minimum = this.options.minimum || this.range.start; - - // Will be used to align the handle onto the track, if necessary - this.alignX = parseInt(this.options.alignX || '0'); - this.alignY = parseInt(this.options.alignY || '0'); - - this.trackLength = this.maximumOffset() - this.minimumOffset(); - this.handleLength = this.isVertical() ? this.handles[0].offsetHeight : this.handles[0].offsetWidth; - - this.active = false; - this.dragging = false; - this.disabled = false; - - if(this.options.disabled) this.setDisabled(); - - // Allowed values array - this.allowedValues = this.options.values ? this.options.values.sortBy(Prototype.K) : false; - if(this.allowedValues) { - this.minimum = this.allowedValues.min(); - this.maximum = this.allowedValues.max(); - } - - this.eventMouseDown = this.startDrag.bindAsEventListener(this); - this.eventMouseUp = this.endDrag.bindAsEventListener(this); - this.eventMouseMove = this.update.bindAsEventListener(this); - - // Initialize handles in reverse (make sure first handle is active) - this.handles.each( function(h,i) { - i = slider.handles.length-1-i; - slider.setValue(parseFloat( - (slider.options.sliderValue instanceof Array ? - slider.options.sliderValue[i] : slider.options.sliderValue) || - slider.range.start), i); - Element.makePositioned(h); // fix IE - Event.observe(h, "mousedown", slider.eventMouseDown); - }); - - Event.observe(this.track, "mousedown", this.eventMouseDown); - Event.observe(document, "mouseup", this.eventMouseUp); - Event.observe(document, "mousemove", this.eventMouseMove); - - this.initialized = true; - }, - dispose: function() { - var slider = this; - Event.stopObserving(this.track, "mousedown", this.eventMouseDown); - Event.stopObserving(document, "mouseup", this.eventMouseUp); - Event.stopObserving(document, "mousemove", this.eventMouseMove); - this.handles.each( function(h) { - Event.stopObserving(h, "mousedown", slider.eventMouseDown); - }); - }, - setDisabled: function(){ - this.disabled = true; - }, - setEnabled: function(){ - this.disabled = false; - }, - getNearestValue: function(value){ - if(this.allowedValues){ - if(value >= this.allowedValues.max()) return(this.allowedValues.max()); - if(value <= this.allowedValues.min()) return(this.allowedValues.min()); - - var offset = Math.abs(this.allowedValues[0] - value); - var newValue = this.allowedValues[0]; - this.allowedValues.each( function(v) { - var currentOffset = Math.abs(v - value); - if(currentOffset <= offset){ - newValue = v; - offset = currentOffset; - } - }); - return newValue; - } - if(value > this.range.end) return this.range.end; - if(value < this.range.start) return this.range.start; - return value; - }, - setValue: function(sliderValue, handleIdx){ - if(!this.active) { - this.activeHandle = this.handles[handleIdx]; - this.activeHandleIdx = handleIdx; - this.updateStyles(); - } - handleIdx = handleIdx || this.activeHandleIdx || 0; - if(this.initialized && this.restricted) { - if((handleIdx>0) && (sliderValuethis.values[handleIdx+1])) - sliderValue = this.values[handleIdx+1]; - } - sliderValue = this.getNearestValue(sliderValue); - this.values[handleIdx] = sliderValue; - this.value = this.values[0]; // assure backwards compat - - this.handles[handleIdx].style[this.isVertical() ? 'top' : 'left'] = - this.translateToPx(sliderValue); - - this.drawSpans(); - if(!this.dragging || !this.event) this.updateFinished(); - }, - setValueBy: function(delta, handleIdx) { - this.setValue(this.values[handleIdx || this.activeHandleIdx || 0] + delta, - handleIdx || this.activeHandleIdx || 0); - }, - translateToPx: function(value) { - return Math.round( - ((this.trackLength-this.handleLength)/(this.range.end-this.range.start)) * - (value - this.range.start)) + "px"; - }, - translateToValue: function(offset) { - return ((offset/(this.trackLength-this.handleLength) * - (this.range.end-this.range.start)) + this.range.start); - }, - getRange: function(range) { - var v = this.values.sortBy(Prototype.K); - range = range || 0; - return $R(v[range],v[range+1]); - }, - minimumOffset: function(){ - return(this.isVertical() ? this.alignY : this.alignX); - }, - maximumOffset: function(){ - return(this.isVertical() ? - this.track.offsetHeight - this.alignY : this.track.offsetWidth - this.alignX); - }, - isVertical: function(){ - return (this.axis == 'vertical'); - }, - drawSpans: function() { - var slider = this; - if(this.spans) - $R(0, this.spans.length-1).each(function(r) { slider.setSpan(slider.spans[r], slider.getRange(r)) }); - if(this.options.startSpan) - this.setSpan(this.options.startSpan, - $R(0, this.values.length>1 ? this.getRange(0).min() : this.value )); - if(this.options.endSpan) - this.setSpan(this.options.endSpan, - $R(this.values.length>1 ? this.getRange(this.spans.length-1).max() : this.value, this.maximum)); - }, - setSpan: function(span, range) { - if(this.isVertical()) { - span.style.top = this.translateToPx(range.start); - span.style.height = this.translateToPx(range.end - range.start + this.range.start); - } else { - span.style.left = this.translateToPx(range.start); - span.style.width = this.translateToPx(range.end - range.start + this.range.start); - } - }, - updateStyles: function() { - this.handles.each( function(h){ Element.removeClassName(h, 'selected') }); - Element.addClassName(this.activeHandle, 'selected'); - }, - startDrag: function(event) { - if(Event.isLeftClick(event)) { - if(!this.disabled){ - this.active = true; - - var handle = Event.element(event); - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - if(handle==this.track) { - var offsets = Position.cumulativeOffset(this.track); - this.event = event; - this.setValue(this.translateToValue( - (this.isVertical() ? pointer[1]-offsets[1] : pointer[0]-offsets[0])-(this.handleLength/2) - )); - var offsets = Position.cumulativeOffset(this.activeHandle); - this.offsetX = (pointer[0] - offsets[0]); - this.offsetY = (pointer[1] - offsets[1]); - } else { - // find the handle (prevents issues with Safari) - while((this.handles.indexOf(handle) == -1) && handle.parentNode) - handle = handle.parentNode; - - this.activeHandle = handle; - this.activeHandleIdx = this.handles.indexOf(this.activeHandle); - this.updateStyles(); - - var offsets = Position.cumulativeOffset(this.activeHandle); - this.offsetX = (pointer[0] - offsets[0]); - this.offsetY = (pointer[1] - offsets[1]); - } - } - Event.stop(event); - } - }, - update: function(event) { - if(this.active) { - if(!this.dragging) this.dragging = true; - this.draw(event); - // fix AppleWebKit rendering - if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0); - Event.stop(event); - } - }, - draw: function(event) { - var pointer = [Event.pointerX(event), Event.pointerY(event)]; - var offsets = Position.cumulativeOffset(this.track); - pointer[0] -= this.offsetX + offsets[0]; - pointer[1] -= this.offsetY + offsets[1]; - this.event = event; - this.setValue(this.translateToValue( this.isVertical() ? pointer[1] : pointer[0] )); - if(this.initialized && this.options.onSlide) - this.options.onSlide(this.values.length>1 ? this.values : this.value, this); - }, - endDrag: function(event) { - if(this.active && this.dragging) { - this.finishDrag(event, true); - Event.stop(event); - } - this.active = false; - this.dragging = false; - }, - finishDrag: function(event, success) { - this.active = false; - this.dragging = false; - this.updateFinished(); - }, - updateFinished: function() { - if(this.initialized && this.options.onChange) - this.options.onChange(this.values.length>1 ? this.values : this.value, this); - this.event = null; - } -} \ No newline at end of file diff --git a/library/cropper/lib/unittest.js b/library/cropper/lib/unittest.js deleted file mode 100644 index d2c2d8171..000000000 --- a/library/cropper/lib/unittest.js +++ /dev/null @@ -1,383 +0,0 @@ -// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) -// (c) 2005 Jon Tirsen (http://www.tirsen.com) -// (c) 2005 Michael Schuerig (http://www.schuerig.de/michael/) -// -// 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. - - -// experimental, Firefox-only -Event.simulateMouse = function(element, eventName) { - var options = Object.extend({ - pointerX: 0, - pointerY: 0, - buttons: 0 - }, arguments[2] || {}); - var oEvent = document.createEvent("MouseEvents"); - oEvent.initMouseEvent(eventName, true, true, document.defaultView, - options.buttons, options.pointerX, options.pointerY, options.pointerX, options.pointerY, - false, false, false, false, 0, $(element)); - - if(this.mark) Element.remove(this.mark); - this.mark = document.createElement('div'); - this.mark.appendChild(document.createTextNode(" ")); - document.body.appendChild(this.mark); - this.mark.style.position = 'absolute'; - this.mark.style.top = options.pointerY + "px"; - this.mark.style.left = options.pointerX + "px"; - this.mark.style.width = "5px"; - this.mark.style.height = "5px;"; - this.mark.style.borderTop = "1px solid red;" - this.mark.style.borderLeft = "1px solid red;" - - if(this.step) - alert('['+new Date().getTime().toString()+'] '+eventName+'/'+Test.Unit.inspect(options)); - - $(element).dispatchEvent(oEvent); -}; - -// Note: Due to a fix in Firefox 1.0.5/6 that probably fixed "too much", this doesn't work in 1.0.6 or DP2. -// You need to downgrade to 1.0.4 for now to get this working -// See https://bugzilla.mozilla.org/show_bug.cgi?id=289940 for the fix that fixed too much -Event.simulateKey = function(element, eventName) { - var options = Object.extend({ - ctrlKey: false, - altKey: false, - shiftKey: false, - metaKey: false, - keyCode: 0, - charCode: 0 - }, arguments[2] || {}); - - var oEvent = document.createEvent("KeyEvents"); - oEvent.initKeyEvent(eventName, true, true, window, - options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, - options.keyCode, options.charCode ); - $(element).dispatchEvent(oEvent); -}; - -Event.simulateKeys = function(element, command) { - for(var i=0; i' + - '' + - '' + - '' + - '
    StatusTestMessage
    '; - this.logsummary = $('logsummary') - this.loglines = $('loglines'); - }, - _toHTML: function(txt) { - return txt.escapeHTML().replace(/\n/g,"
    "); - } -} - -Test.Unit.Runner = Class.create(); -Test.Unit.Runner.prototype = { - initialize: function(testcases) { - this.options = Object.extend({ - testLog: 'testlog' - }, arguments[1] || {}); - this.options.resultsURL = this.parseResultsURLQueryParameter(); - if (this.options.testLog) { - this.options.testLog = $(this.options.testLog) || null; - } - if(this.options.tests) { - this.tests = []; - for(var i = 0; i < this.options.tests.length; i++) { - if(/^test/.test(this.options.tests[i])) { - this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"])); - } - } - } else { - if (this.options.test) { - this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])]; - } else { - this.tests = []; - for(var testcase in testcases) { - if(/^test/.test(testcase)) { - this.tests.push(new Test.Unit.Testcase(testcase, testcases[testcase], testcases["setup"], testcases["teardown"])); - } - } - } - } - this.currentTest = 0; - this.logger = new Test.Unit.Logger(this.options.testLog); - setTimeout(this.runTests.bind(this), 1000); - }, - parseResultsURLQueryParameter: function() { - return window.location.search.parseQuery()["resultsURL"]; - }, - // Returns: - // "ERROR" if there was an error, - // "FAILURE" if there was a failure, or - // "SUCCESS" if there was neither - getResult: function() { - var hasFailure = false; - for(var i=0;i 0) { - return "ERROR"; - } - if (this.tests[i].failures > 0) { - hasFailure = true; - } - } - if (hasFailure) { - return "FAILURE"; - } else { - return "SUCCESS"; - } - }, - postResults: function() { - if (this.options.resultsURL) { - new Ajax.Request(this.options.resultsURL, - { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false }); - } - }, - runTests: function() { - var test = this.tests[this.currentTest]; - if (!test) { - // finished! - this.postResults(); - this.logger.summary(this.summary()); - return; - } - if(!test.isWaiting) { - this.logger.start(test.name); - } - test.run(); - if(test.isWaiting) { - this.logger.message("Waiting for " + test.timeToWait + "ms"); - setTimeout(this.runTests.bind(this), test.timeToWait || 1000); - } else { - this.logger.finish(test.status(), test.summary()); - this.currentTest++; - // tail recursive, hopefully the browser will skip the stackframe - this.runTests(); - } - }, - summary: function() { - var assertions = 0; - var failures = 0; - var errors = 0; - var messages = []; - for(var i=0;i 0) return 'failed'; - if (this.errors > 0) return 'error'; - return 'passed'; - }, - assert: function(expression) { - var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"'; - try { expression ? this.pass() : - this.fail(message); } - catch(e) { this.error(e); } - }, - assertEqual: function(expected, actual) { - var message = arguments[2] || "assertEqual"; - try { (expected == actual) ? this.pass() : - this.fail(message + ': expected "' + Test.Unit.inspect(expected) + - '", actual "' + Test.Unit.inspect(actual) + '"'); } - catch(e) { this.error(e); } - }, - assertEnumEqual: function(expected, actual) { - var message = arguments[2] || "assertEnumEqual"; - try { $A(expected).length == $A(actual).length && - expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ? - this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + - ', actual ' + Test.Unit.inspect(actual)); } - catch(e) { this.error(e); } - }, - assertNotEqual: function(expected, actual) { - var message = arguments[2] || "assertNotEqual"; - try { (expected != actual) ? this.pass() : - this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } - catch(e) { this.error(e); } - }, - assertNull: function(obj) { - var message = arguments[1] || 'assertNull' - try { (obj==null) ? this.pass() : - this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); } - catch(e) { this.error(e); } - }, - assertHidden: function(element) { - var message = arguments[1] || 'assertHidden'; - this.assertEqual("none", element.style.display, message); - }, - assertNotNull: function(object) { - var message = arguments[1] || 'assertNotNull'; - this.assert(object != null, message); - }, - assertInstanceOf: function(expected, actual) { - var message = arguments[2] || 'assertInstanceOf'; - try { - (actual instanceof expected) ? this.pass() : - this.fail(message + ": object was not an instance of the expected type"); } - catch(e) { this.error(e); } - }, - assertNotInstanceOf: function(expected, actual) { - var message = arguments[2] || 'assertNotInstanceOf'; - try { - !(actual instanceof expected) ? this.pass() : - this.fail(message + ": object was an instance of the not expected type"); } - catch(e) { this.error(e); } - }, - _isVisible: function(element) { - element = $(element); - if(!element.parentNode) return true; - this.assertNotNull(element); - if(element.style && Element.getStyle(element, 'display') == 'none') - return false; - - return this._isVisible(element.parentNode); - }, - assertNotVisible: function(element) { - this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1])); - }, - assertVisible: function(element) { - this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1])); - }, - benchmark: function(operation, iterations) { - var startAt = new Date(); - (iterations || 1).times(operation); - var timeTaken = ((new Date())-startAt); - this.info((arguments[2] || 'Operation') + ' finished ' + - iterations + ' iterations in ' + (timeTaken/1000)+'s' ); - return timeTaken; - } -} - -Test.Unit.Testcase = Class.create(); -Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), { - initialize: function(name, test, setup, teardown) { - Test.Unit.Assertions.prototype.initialize.bind(this)(); - this.name = name; - this.test = test || function() {}; - this.setup = setup || function() {}; - this.teardown = teardown || function() {}; - this.isWaiting = false; - this.timeToWait = 1000; - }, - wait: function(time, nextPart) { - this.isWaiting = true; - this.test = nextPart; - this.timeToWait = time; - }, - run: function() { - try { - try { - if (!this.isWaiting) this.setup.bind(this)(); - this.isWaiting = false; - this.test.bind(this)(); - } finally { - if(!this.isWaiting) { - this.teardown.bind(this)(); - } - } - } - catch(e) { this.error(e); } - } -}); diff --git a/library/cropper/licence.txt b/library/cropper/licence.txt deleted file mode 100644 index b59e02917..000000000 --- a/library/cropper/licence.txt +++ /dev/null @@ -1,12 +0,0 @@ -Copyright (c) 2006, David Spurr (www.defusion.org.uk) -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - * Neither the name of the David Spurr nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -http://www.opensource.org/licenses/bsd-license.php \ No newline at end of file diff --git a/library/cropper/marqueeHoriz.gif b/library/cropper/marqueeHoriz.gif deleted file mode 100644 index 25317e5738bfcce43707ec0a0640533f69eb8fff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1125 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 PPffC!10NW#8L$7@U6jV2 diff --git a/library/cropper/tests/castleMed.jpg b/library/cropper/tests/castleMed.jpg deleted file mode 100644 index c35a6f554a21eb62f3c3e3580e616a4feee8748c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50584 zcmY(qcQl;O8#cbXdhcZsy+mIYL3GhulvP$IR*x1!^cp?7U7bW-%j#Y9x(LxrBBBKm zB_tu`_4&TPKi=Op=gfJ|JTuR8-!pU0ecjiY`M3IS8$hkAsiO%1f&hRgcLnh81VHmB z(AhHt00iIz008#8rc(fy>JuL)7r>K&yA~iGfEo{kM+gA$1Ofo&+5o_4-oFh%9DtgP zjEtO&nw*@PiHd@XiItw3nx2(|=|6C=GqK!(iJhH?Pk@hyU0fUr6&F|e{{u)vMMXnL z!$3>RKu>d5Sm+rU=~?($SlC!t_#r&(ci@2tiwOt_hzUzeLm<-9Dk{qV?eJdUoy~qmsp2F=Xm2#Xx&E9E48* zBqRjgS^1xVKpHLyYE@$pr=wpqEjJ{yd{7ck<*aF5&EylEQ;a_ke%8Nr0Qp^C5Dgy9 zUH|JQ_~uNFYV!3b0}_&i1Ps?wvQ)*5uF33f_D6xNx|>P3rXV2o9Q@Wm+N)fq+@Qz!c%_FPhnWX+4!N#@u<+b9A3($@bY$} zb&No#FjG{ueN1);sljO?2`Ao4f~xSqY@S%V&k}>4?{_SWIS;O{hx|f{@N`|De2wY@ zi!hf#MM0b+gIRj)qX+_MO`|X8Iwv^NNF3ryfJSfNu*- zhr2tX=3384V|h*RACS}MJ;r|6o?PHtbeRVX`!}F4V042;}dHGx=W~(H7vFsIT{c>Vc z!1XI_1(UW;g2Lp>Uv?YfVZS%O#cEG0EiVVghxa(vHLqwO5I20MVZq@h_hh#NZ*Bg@ zb1I`YmP*(HI|Y}qR2bkrPr&vP!Tz*O(_kl~r{q_uj9!iGN<9j)6riNNL-{?{$tGAEzjr8WD*e99nA5`!wCCE$Ple4|==JeWKFTn+{@NP7?HO>4$RN`6E zl7z?ly=`Cl^et15?2Nuu><+>ud3ietW!M)Cuyb3w$>1K>bsAruU6*XMIV~bs`Rcri z&Heqi{b{+WXT0RhV$RpCLB%DKPt$zn1SaLRD|}cTv2$9bJ~;xc5cz-@e&&?Rue>UJ z*t+qD@F`;x&qc4FbB^sIyu07>On+c-t3b_{h)wWiXi4O2d3P6yb~w)Q@KZz1WXP4t zD;0sDV98rmMgAqecVN-Sq4nAoqkIpqJn)ZHSTukRXEqFZQ4|NCZ zoV_4REV8xruq1J`BH;ePDnqfKNUPG!?%bM_-yX5%u>~E)8uFXV>l55OahiEwIc7Ti z)v?+2kus=jbo|{|7P&Lpm!E-YF=V)9`C4Y&Lb2kBZe^V)AD7$%r7&`$j=bWCO7DLF z1^vc%`7`;*(#@iH^_jNyV6 z;$f|P@-z$W&c!N@4mP*a3K4(h+e?zuLi}D(DJK+&m%lDqc6rFZiX^ROoeG?LEl|q; z)BBZxp4TYqgSpXDm-S`yUe|BADmy*9O1x$Z?}r=V#&$@OV>b=g>9ztJ1fF@P(7Zzs z*}_wXhT+aHQOXuHc6wSW+eudJ&-}R;jd?0z@|!ETwab>-7snxBSM1y5yikk&=OQ;L z9Fps=H{Qz@2vpi6TYtZp)Vn4LvB;h`(^2OpoAT$Ok#;-FmieGL_QLjF8(&4qOX-qR z!@9scANf@;ZQ(KMhNA?vE~Rn)%S(B;o`9y>=;nhEt%t8g`1(YAN|E36+h&QL9&8Gz zuV^#Tf+?%qs+kBX>Uz|=sKAS^)Z7$F@vtU>+uJDnJ@LIZw+GJHwWeRnlK2yl$TS(pbS-qc)I~FfAND`udHtMwGl~ z^?vSm_NRM&HrIQHSTvc+haW0G^9_z|^IiJpBfqW8Go<<)Fq1tvXZbgH#QZ1rUMH zg8eL9{9SoA@K6GzYb5pBLccXz-MPl^ip#RPcJ!Xm2)VxQj*NLR!Co6^Y3NuS)nI+| z*X6qJ_i|vNhR{5xl-n5y(q66C`C4f|W&O@W`Azanu>${;EZc@YxKmcx$pZ=QmwLt( zlw$^Bk+HjR1;19PapW?5#$$GmtxXob5TW(n&1+k9Zits(oC;mFw;l)R8KaOTDLe%x zPbl7FUUW6BBCs3TPanrjmG<#N@ONNe;k)ooQ9aWIBpuMXANG zBffa++UtD1o}XK!=epmMYLAmu(UtGD%sm4Pd0Ux#rR_Q-`yk0zokETmi0=1NGw!tC z29q_n&wA-;!wj+OzlHqxB(f8u?1o%zO|bLJY?N=b%@CGj>BOj`R)wcM81gUmJ!f!<`=H;zDjR5f=m|VLJd4F;^aH(`boAN^G#f^FE1OBc5qu4v`U}6| zQeurZzb{|{nN2!6$;cD|%g%znafh~1gr)8Mw^T@-WGrt%Iyv1`(8`-bDJeSs%0@n( ztf*u$kV3YLWM$N*$zoJJ?}{2`mNd{?5=frnU`>qblJ9fCDpCfhCt=(EjN|@h&hs`J z{z|17)%A7nT}g0YN(f25v;kyYIG}B$9qW?Z97NJ9*AH9Ed_zI+RzO87(EVM3;9^f) z)u;JnwJqyb$z@VeH+QGr01a~A=j12#cBZU@3iysD>QT^A?Rjf{;|!9CW6uOToWI!g zdhA{y1A~)6IkoYjO(2G!RCfP~6ZclF-U2bWBE)2>fRF`)%>yLFO5w`ec6W;N|f^Z%I`q`l3m%Jx!am zzI9xc*EU++rEHr*`?Z*^u9zyV+X{_i&Vveb_&Q^DpLad95{= zqd3!>m!8=nH@&`+s^1mywzuZ})#nTUQuO3FpZgc8xOo=e!mDEb-+0HDX2)k?NA4et zU{wNACifp1IJer+Z4z)k6zi(xzV37n>=dPchqJBFVhBNLu;aHrB;{|AZ`AIUtMxB` z_Qp_--nglbtbDobLFfY$jh12xk9M}v$_#>mfvg2*4lQ`U;VEZ!G8~rp`Z@1mory8+ zv_;Lj!2Mc+rM-3{V-p2&KSp65!V>HJh6KSKHy4ZQLZA6yMN!vvqf({$whulDc%EeW z`go^}g*b^dPYFfy`Tb2APH((~XuQSNk1rd`JS>X*s)^z^Xj4PIFrsAOE~}yCh3dVR zC!=+j2>*qU^Uz#%3dQr+4{!q&*OQT^rlf4RihyV4tPF<**rY^v(4N$TGvM zdEo2Jb)$5+2VW9l?N&i$AW8vJa(`2DZXR2nYVWw=6KLKlG4@h|Ur zr6$Jb?@VL*J&ir@)dx9rksOu2_v+;+m#KOYy!zeKUFo@le=cK#i9spfuSd(K>}cBu zCUl2w#;af8<1KdYHC>)HsXr_6OMtQ!uoEy4`P4n6wts@OM}0Hil1PwFiyiN^kUR2Q z->D_(glv)sXX3w0gV)mstyLy{m`&~tR+J%)?reV_A}rVCGu0~kvq(|p#f+x_-n#4H z&Z{@|Lr(*FmD|oS=ii@(%xUB&B)`4Dnv8FVz7iuyMOlu|2!}J)Tn>CUZ{q(}RAZNox47CMfHq7G-}Y{qacw#@ zK9DbL4jK8wzWG+}kZ|tNI|68kg}C2pPfxP~enwc9CX+%}=XbZchyB^62Q6P{;&WW* zGnaD8+?rC&yp(qj?HB!9F58?mr(IFSx=*@9RLCZhC_O^@QbGgXjH{ROe9@b(F7SLR zT`GebKREn`bfKK}4~?YLv$veRY{cZu+neNwl$I}RRHD#Mqm|jyJ%2S7&<9?NBiDO2TgJ!tPxd`Yk2_L| zvE!&v+y>mtvqx~Rr%}0hi~nckXtdywP>Q3EY60>(-~toyHk)v!)-Tn@<(r9OnTL6S z84YY@_R!>jLq%%TW^#hf-6Ojw5FUU&4C95}YAVQ#i~W7g@LTLK)jNzW;2>7WBW15r zwap6awxg^U89DGmQG8WcZdy0jfQqcP-$HBYU~G14_H=yM>+{Ea<=4<{tB*#02bZn& zQxS~2YsX3kpB`5x`E}*L3|kIanMV{_m3&t(J~tHMKZ89vo1i;Gi$lU*37_%0cM!Ji}!kynUwJ! z_(2+gUr}iTR4-{PNR;MK(kl(FGg++*mmxDQ%4)dtHCwGWx#+PtPzJ>&k+u48{g{=+RxSAqGOzjc{& zot=?7ThnjM)PnT4$$LU{YX>i zdI{00*A_>5ss#sXWu@_-2e|W?;^(dtwtMQk5auLGa4y{JgWfTf-zT@sqNSLKJA{^@soKQ6vX!7>zDQC_o2mW-(|<2wK1HcB>xQhJvXCKI+|?$ z;ZkX|>7G)#)!=V<(yGz_)ur$`V_IkxU;19yt3dvM+aldR>p9L{P5E5{!dvlV@1MK7 z44l^e04uJOo&4Y`vO7{(?diNMcy4yNHFc43`em;4l)>tB%3|U4W!lrz=<1#>OyDhA zF0xzy=!a+V@+n5{bWdXIz4D#xMSQ2k0SN%(V-Y}9vV)2fuMj!jXXP^|SL%-OD+DRU zbZm1OMWsZ$LJCxZL6e6LfTRP_zX>rc$*=cRx130_MSctL9HK239_u? zdik0E$)GbJADg(Dzbl{pJ5G7PP!ka#QC#>lmM$lhm@ldb1)lBfq!)fz+;lo~*FDz^u^)4ggL{dXkP?AfD{@w35{3?ro09IY#xz7`L~)y-5P zrv!DA8#U_4z2Oa$iStU7{=Tb7#soq|q5N(ZNJd7`IrKHL;}_gi1ogZXph`oXpEyk+ z%ZrjKiT>)jAvu$JW(|K%1o>MX7ne^fkYn)AF&1K_77A}!sU3%UWLq`?#2kM|AevVaF}#h za_*WV(-YbbVKx-hstosm>g z!%5su9NEC!%n5Ar8a10ysNZ$F95Wm*Mh_x{;O8`^R8HU=8KldY;1N+GhK?BT=EcK_ zxS1Rj<5c#E&J=#rkl_8qlVk3RPDcoUM{tkSv;m;9Vas?kL(Uipk|?7$xLH?dqRLMS zJhosSe2$lABemo@QTlU^(X;B=%xZ6FXX1m2p~v*U{`R*)%qtup@eI~$Jm%M*JL6?+`NWW&U-VQ>|OszTwcxV z8Mr0Mq zA|h4V)Hj5t60$98OpVlE5)%SC0S>?7)DwwvO=GW2&y0!?A-UvDyaa(}e13_d&T00TAME9l}XAa)0coJmUh z%r&7907AV2&{}EpI+?#|DND1&TYgt-HDtafQyXn48-2zeP!x^Cf&52!nX7@RRE(R{ z1G8$tEMbrz1&E&@TBntfWXjhOM1I!b+wh`}*CehDO573?rFOnUzAc#&RjzGq+wj8g zo`QqQYc72uzoQ~zBs2-S0>Xl22O)FNQ<{L-DKcVv_w*6{R8W+qIt^JicSz^u zCsC6(L0lh3cSwjb(~ru1Rd8%omNb!qqpP``mHHMJ(nma^pzR*jF<}A}*atw%<41}| z+?ZXeFstoC5-y|sc_n#pWMqV!0C#I5bRmNYyl(vex`xCm{zOk>6t;sb^Utiz-Tv zIZcT=0(&i(ukJWplEcW=h&|m$qO5tciKp60hgNjh{nr3lB;-_EqxuiKXP-7ylnXHy zfvx=tDV$eynv(Y_{@{tZ#3o9%5lR4kKCU`1+g!70@_R2~*<<#I34uxB(+1wFA6iTU zWe6WRLR94dv?M{};v815IGHyX$|r=3@&%IY1&$hgpVf#Qkea#lj(P#NA4H`hR$CXk zue$^D)~_Us1P2+5^6(=V_)Y6`1)FkMSs0D&xz+NgD7n|;lMpDs+UhS}Nz*xy-5loF zq1>}h0wi(b>hEU~FPV9$$osWN$nji76z1NH(`={ip2C&wP%y4gQ$<{O`-J8%mhyUEmav~+I=lq5$EN#($IQM@{G$;`K25eGNI+L zHiu&)U0_gvnSuN!KP!rmd%67Mt+5JY*<%4(2U)`4SxU>%ODO9A*$-fXPdhB#ChVLa zm>@@2Vzlf!EkofG>jVpQwtEwuXyF8lSYXQ74X))Bp^_u#JdbQydF?Xv1$AOogxi+% zPZ?hY&}2}1n82I4+4NWim;w7roV?)3zYYk*gy;@gHpJJ7Ev8yTJ1#-+yTGIu12C<` zk-#91IkHugM|lCu=jAud!Mfqa+!yu5N7f;1066&-tPNk_l^ zhjB=|u3!DzAagYS;A2%No0UzLCPH@fqWVZ7{+x7A)0qSBkbbvb0~Q4&@KRC1&g{B$ zrcMnW*uT?i@&(7K>C7>+Li#Q2Pv5fZBK=2+^1xuQnrrJA$)rWk*`k=-BBMmG=M{R2Gz z{AUm0taiN8tU( zBXD!)+>G3eQK-_NEx%PJuZnI`rJ04!Ea>>@&Xf}n`g6YtiMPSW@qV&H#Qy*&ql_WE zi-GNZKieu)fi6GpN0UXF_sNvM9EC33i{`3CMe*C%dq>(V^pRS)SNjPyh+&=($ zVnpmue~>>ar6~2Y1y(?C_`?)c*`&+Jm@(JsgH9Vkzo$|2Vncn z!O00MBq!$(0mhE(bKX25=4nvHXP!o?42L@@GmFK1IgQy&cls|}lsl5mJrS1!?~Y=U z;88_%zu1OR1ACgBP;P|dBs>JKzU+K_oLQ6WvAX#q2&Y6oehDWolEB23@TJ@&3W{Uc zfAI*84UPu>8Yp_SBR~UjgmB10%=JIXCMEJk>i;^ACR+Rxkxi2=p~+LvN$qY*!7u%U zDjv5xM*U9A6+L9mk3XW!iF=j$J5j5Yj+&!LtuuCHL^y_%8}Iy849_d(IOl^!=rJ9& z2)6@XCKM{^TKWkYK|I1a3i(Z3;a4QE;Lm#jMa5q@L~S4Zq>)WTC_&})abvzfIj+R$ zyWjY8#-fr+Q^WkI_g%MN<@#jr1EC}roVZEq2c^f^a?I>c9D?J5$J4#Ino_5ksY?8i zsOaCS-2U$QMX9?VWg#Tr!BKM@UEy4$o#Fu(a#zdO@KaUC14?#h{Tqe1MmA_FnlS=e( z1W8>^O7ahlM*r!k)N7 zAvBUoN*O3r^nHApaYkOX?9`peL@4AB0ENTt;prcIK9)Fu=IkX+;E-knyMB|^P{oW@ zM`sAa4=Nb}3D^%o#V3NH{Qe~YfAr6RAZ8^J)H%t8J~)={w`@^04`5P>Umsk;HBo96 z8;xx1!l(8liJAj}cL$4rS%^nUlzsr-W(Yfv@6VCBR2-5XH9l1?5lsywrUN5WUjkH9 zmup!H&Ydb|pNvHCoswgzcpWgS)@)G5Qu|cq-~sIt2VS<{lBp`b8ug6KN)p>KR2h2A z%%4PsY+Fd8aNsQNYzYeSxQW!6(bNgTW|YHQS!H}M5=)+2snXxZ!OrJ}^o5?KOx&2t zn3-yL zILfsPJ8S(pXOARpoW?RH?^AtC{@{R|EHkiB;K(Ru0E;&=dAnGzQ76}LY(H00&cBO<6A{m`4c%Kaw19~Nk{53gnrZcH5dr9d_6@OET25|D09*%QyUIhQ*teHZF zQF2nriDnQ(l^CYR+E9~pvqZ>o>TMi?F2)?-6gw$V$PoP756VG=8<>?KMy56;4G|kU zo-;u}mVdMsgNssk^mp*dINwxT!II{I0 z!0FLVFUO;lKf_1=0Pw%${{S6--u^H80RM|VxA+SBQuV|T3tFuIdqPWAc2`P zr6q~^XQk-_29Y=oL#-7$yJ?D?HDkaiX0@3?9zHr#jF^=AlA~^=B_7r3*m~OZO+kk@ zPWF+AwaF~=3%m`_sFSFZRn=9e^4Y+4E7!d?-)~)n2g7zF#n~gP`nw3n5{EFAHDr|j za4JVNm4YVeJ_E4~`o~I8)mX20zNkytN(`sURKtYbn7`H-C%8zHINFh21sR6`NF*|4 zVb3p&5-G{pMyoSyE%@G!>y_Ap805%MOLr2);om@RMuE@D6C5H?;t~89 zR;a{ebgDVg=No9o>}bqV=F@`iYg;WkL|V0IqkL_Z<>R=+;KTDPc~|qayUT#saV|PpilH)D^-YGbbm=Aa$z)_&Mu}sBgw! zVKTc0bE|7V0+PYWIMhBhLP+8OLAb;AQ2L?QVczozX&^(TxOMsGtVPRg z>ZIMF7P|l8ZpR?w0m%}q&?J!>o+tqhA{tdEAxNqkISAyuol4AL2FIxv=kfSG>TvOf zYmps8dkr&#-Lmntv%O1hU9dyri*MPE8 z(9|UUExOu?@|6{nPjySi(O1bCPvKaTF$^q9K7ZS7>!@d)pIlht|AH_=uwuX1ThOX< zDG!fmlDdA716;xn%v-JuO*7LY9r({O@W6~=^@ZE|Vh8*K^lp}^!<8h6M+oUYjZD%Q zI)EJ1&mQe?VI1qVR%kpv)8+yi)J;-3%zGI7^V*(Ov?bFr3<^Q$U6UO+>7t6bw6DhB zxO(c?KD%$jURV9%JNl6=ys2gB$gW3`VhQTG&dkMIOGK9hUHrM@%1l(u(l*WQNT5n( z-*Upaf2UNTGD&FajVZ2BhynFqDWy-%zYfIu+Pb@dKg$lH11O$$AG4&_@&uaOT)D4U zwiu>xefhrD^E9ur=Bf~6h4%KN(f?aI@vF#z8HM@@h2rE&T-jofQOx+CP{-#nZ#lHd znM=4v<^~dE&%0c5>rREMDm_5kQQUusU%|27EPTZ=CBNNf4WeGq+H9oX zrBiC5PMxKrP8u0V07{T1d0UYq6)HFYzY&Dd2b>6CJpMMP3O@i@GpKe=h32N?qp=CG7}uB>$H)+(z)1#*jv z_9%+1j=2HlVUCfc7a;0p>YvHKimC;th@#8f$oJ%CeWeH^#uL6tCs)*9UNsMSu9_D! z9JMrHgcsW1H2KVHQ8WeyRfs8N+C!C@n#j6BLK#Z-b?Y#mFH#$m2X=?8k?U17!3^d{ z>=)4;-v}NO_=?C7l7rAv7!gL{0Y^7-9Bu*?UFD3lp7a`ptkTOIi9B8Cw>W+G+3AC6 zG_T+e3sF&}PtpmsY;^T~CCezq8Y3<;5@+H8x>ObY$NHR!jJ`t|87-KT{%6w?#* z{R4#av!%^f7*L`@ItZTzO{l1XcH`~~bntsQf}_A2cn`hftib5buPp`r5;q=M$8{C6@Ai-p7>Lh~W5Hr0IriC8y)tiz|&?E!S^PiX3=0}gQ9Pu#9R zlVjJT4mXkTcg|k4%U)TLq66V*W*P|z+UkJDceP|Uf06euGe$rTiR6TWiSKhLz!i1G z-=bGLpWrP|b}|HSIA9c{Bfy5iqxg78M=+zgdZE|jpaJ-g3GpAR1CAlmTHHC8wn95k zbTR1n)tfg%8JZE~O~8_N!q0z2WAi?PkdL>85j`h0Y1Mmw$Ie-w?hCJO9sTb4MbRVs zzAfDMYd>88UporkR}busDjuQj>)vF|2Q5#Z7~ueaO>+A`E6%VS6yZc7lq;4`BH2Ia zEk12J?jFW~>ToqhWe|yEr%V!RB#W?ygid@DSrkDmqqUd<(yY?FzRwPXBR0a~;2B>MjF*IcF5pEOSYH5_er9WAr zbbcui=_oBNb6XtvZmH4qxoxX-jAN|z2RL{`s6u-g*+MDh=os6BJ-z-CE{0nllUW5-*95_iNA=XCT}1GyVxSOJLJ+5H zba^mbc*LzrFjbPm@nt>uPzRAL$08J0S8s9Ah&QXo1hRiytFrp%HKyiTxoO$_?{omd zgL|zt+Jxmw_ayK|9&4n%lUT$0b&bkI$(UFk*jlpLH9l$DB??p5TlX4n-*zf?&-J*t z(0cjgTAt3}TeYdQvspx`Gi+7PL4}xT_s`g{N^txx_pRY7g)!!-g z0w9O-31L|r@vDLP_VadP#;2L08=;Ie2T3VfR(n)P~N;P4+p09&Q>&I+ z1A3+Luh!n;-)_m=SJt{$8VbDf+>U6TTOiom2dYGQ6sQe_fUi&I)mAE~oL68={goaw zjVCVUZCU7+`?t~X34=fvm=IW{@@TiNy1=~r3LMFgBmMCrexqDkbn%0Dl3VwBB+R7y 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 RJ3V^U{{ZIRKl@F8|Jg7^TQ~p! diff --git a/library/cropper/tests/example-Basic.htm b/library/cropper/tests/example-Basic.htm deleted file mode 100644 index 391c2ecdb..000000000 --- a/library/cropper/tests/example-Basic.htm +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - Basic cropper test - - - - - - - - - - -

    Basic cropper test

    -

    - Some test content before the image -

    - -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-CSS-Absolute.htm b/library/cropper/tests/example-CSS-Absolute.htm deleted file mode 100644 index 17e4c489d..000000000 --- a/library/cropper/tests/example-CSS-Absolute.htm +++ /dev/null @@ -1,162 +0,0 @@ - - - - - - CSS - Absolute positioned (and draggable) test - - - - - - - - - - -

    CSS - Absolute positioned (and draggable) test

    -

    - Some test content before the image -

    -

    - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque consequat risus cursus ipsum. Etiam libero. Integer vel mauris. Donec vulputate. In ut augue vitae nibh lobortis tempor. Aliquam hendrerit quam. Phasellus sed orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut sed urna. Donec nunc urna, porttitor a, feugiat pellentesque, varius id, justo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Sed sollicitudin. Integer enim. Aenean sollicitudin. -

    -

    - Integer lorem turpis, dapibus sed, vulputate nec, volutpat a, sem. Sed malesuada laoreet lorem. Duis mauris ipsum, fringilla nec, tristique vel, imperdiet vel, neque. Nulla vel purus. Fusce non lectus. Mauris pulvinar. Curabitur eget eros. Nunc ultrices, risus vitae adipiscing scelerisque, quam mi auctor lacus, non pellentesque augue sapien a magna. Etiam rutrum posuere tortor. Mauris rhoncus sagittis dolor. Donec sed quam. Vivamus vel diam id massa adipiscing bibendum. Suspendisse potenti. Integer arcu est, adipiscing sit amet, convallis eu, sollicitudin tincidunt, quam. -

    -

    - Etiam ligula lorem, imperdiet ac, luctus eget, ultrices at, odio. Vivamus malesuada, justo eu adipiscing semper, nisi dui tempus magna, quis ultrices nunc tellus id massa. Nullam lobortis auctor sapien. Quisque non nulla. Donec lobortis pellentesque nisl. Sed lacus sapien, viverra vitae, blandit ut, fermentum quis, leo. Morbi augue turpis, hendrerit non, feugiat vel, laoreet sed, est. Nunc velit. Praesent lobortis. Integer enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Curabitur faucibus lacus ac ante. Donec odio odio, tincidunt a, egestas nec, scelerisque nec, dui. Cras sollicitudin. Donec lacus enim, mollis sit amet, interdum quis, euismod et, nulla. Nunc sit amet dui eu magna dapibus mollis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla facilisi. -

    -

    - In hac habitasse platea dictumst. Nunc neque urna, dapibus ut, tristique ut, bibendum ac, felis. Donec dictum est ut dolor. Etiam accumsan, velit sit amet blandit vestibulum, turpis quam hendrerit risus, vel interdum eros orci in nunc. Curabitur tellus sapien, rutrum ac, euismod ac, malesuada nec, pede. Proin sit amet ipsum. Praesent quam nisl, adipiscing nec, tristique eget, fermentum sed, est. Praesent ac est sit amet orci facilisis placerat. Sed consequat, est sit amet consectetuer viverra, risus urna porttitor tellus, ut convallis nibh libero in lectus. Pellentesque molestie, erat non vehicula pretium, turpis nisi eleifend eros, sed scelerisque tortor odio non tellus. Nunc leo tellus, faucibus vitae, placerat a, accumsan vel, arcu. In et orci. Ut tristique euismod nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Sed nulla nunc, placerat vitae, pellentesque non, interdum non, sapien. Quisque faucibus, eros sed venenatis sagittis, leo risus rhoncus risus, in pretium sem purus a lacus. Aliquam aliquam leo et diam. - -

    -

    - Nulla sagittis diam. Phasellus vitae enim tristique libero molestie tristique. Nam mauris sem, elementum nec, cursus in, fringilla ac, neque. Nunc metus nisi, dictum vel, vulputate quis, porttitor bibendum, tortor. Vestibulum vehicula. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla ac magna sed purus ultricies euismod. Aliquam dictum. Sed mauris. Suspendisse justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi purus lorem, auctor non, porta ac, vehicula vel, orci. Morbi pharetra massa nec leo. Maecenas et mauris. Aliquam porttitor tincidunt nulla. Vestibulum pede. -

    -

    - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque consequat risus cursus ipsum. Etiam libero. Integer vel mauris. Donec vulputate. In ut augue vitae nibh lobortis tempor. Aliquam hendrerit quam. Phasellus sed orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut sed urna. Donec nunc urna, porttitor a, feugiat pellentesque, varius id, justo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Sed sollicitudin. Integer enim. Aenean sollicitudin. -

    -

    - Integer lorem turpis, dapibus sed, vulputate nec, volutpat a, sem. Sed malesuada laoreet lorem. Duis mauris ipsum, fringilla nec, tristique vel, imperdiet vel, neque. Nulla vel purus. Fusce non lectus. Mauris pulvinar. Curabitur eget eros. Nunc ultrices, risus vitae adipiscing scelerisque, quam mi auctor lacus, non pellentesque augue sapien a magna. Etiam rutrum posuere tortor. Mauris rhoncus sagittis dolor. Donec sed quam. Vivamus vel diam id massa adipiscing bibendum. Suspendisse potenti. Integer arcu est, adipiscing sit amet, convallis eu, sollicitudin tincidunt, quam. -

    -

    - Etiam ligula lorem, imperdiet ac, luctus eget, ultrices at, odio. Vivamus malesuada, justo eu adipiscing semper, nisi dui tempus magna, quis ultrices nunc tellus id massa. Nullam lobortis auctor sapien. Quisque non nulla. Donec lobortis pellentesque nisl. Sed lacus sapien, viverra vitae, blandit ut, fermentum quis, leo. Morbi augue turpis, hendrerit non, feugiat vel, laoreet sed, est. Nunc velit. Praesent lobortis. Integer enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Curabitur faucibus lacus ac ante. Donec odio odio, tincidunt a, egestas nec, scelerisque nec, dui. Cras sollicitudin. Donec lacus enim, mollis sit amet, interdum quis, euismod et, nulla. Nunc sit amet dui eu magna dapibus mollis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla facilisi. -

    -

    - In hac habitasse platea dictumst. Nunc neque urna, dapibus ut, tristique ut, bibendum ac, felis. Donec dictum est ut dolor. Etiam accumsan, velit sit amet blandit vestibulum, turpis quam hendrerit risus, vel interdum eros orci in nunc. Curabitur tellus sapien, rutrum ac, euismod ac, malesuada nec, pede. Proin sit amet ipsum. Praesent quam nisl, adipiscing nec, tristique eget, fermentum sed, est. Praesent ac est sit amet orci facilisis placerat. Sed consequat, est sit amet consectetuer viverra, risus urna porttitor tellus, ut convallis nibh libero in lectus. Pellentesque molestie, erat non vehicula pretium, turpis nisi eleifend eros, sed scelerisque tortor odio non tellus. Nunc leo tellus, faucibus vitae, placerat a, accumsan vel, arcu. In et orci. Ut tristique euismod nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Sed nulla nunc, placerat vitae, pellentesque non, interdum non, sapien. Quisque faucibus, eros sed venenatis sagittis, leo risus rhoncus risus, in pretium sem purus a lacus. Aliquam aliquam leo et diam. - -

    -

    - Nulla sagittis diam. Phasellus vitae enim tristique libero molestie tristique. Nam mauris sem, elementum nec, cursus in, fringilla ac, neque. Nunc metus nisi, dictum vel, vulputate quis, porttitor bibendum, tortor. Vestibulum vehicula. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla ac magna sed purus ultricies euismod. Aliquam dictum. Sed mauris. Suspendisse justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi purus lorem, auctor non, porta ac, vehicula vel, orci. Morbi pharetra massa nec leo. Maecenas et mauris. Aliquam porttitor tincidunt nulla. Vestibulum pede. -

    -

    - Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Pellentesque consequat risus cursus ipsum. Etiam libero. Integer vel mauris. Donec vulputate. In ut augue vitae nibh lobortis tempor. Aliquam hendrerit quam. Phasellus sed orci. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut sed urna. Donec nunc urna, porttitor a, feugiat pellentesque, varius id, justo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla facilisi. Sed sollicitudin. Integer enim. Aenean sollicitudin. -

    -

    - Integer lorem turpis, dapibus sed, vulputate nec, volutpat a, sem. Sed malesuada laoreet lorem. Duis mauris ipsum, fringilla nec, tristique vel, imperdiet vel, neque. Nulla vel purus. Fusce non lectus. Mauris pulvinar. Curabitur eget eros. Nunc ultrices, risus vitae adipiscing scelerisque, quam mi auctor lacus, non pellentesque augue sapien a magna. Etiam rutrum posuere tortor. Mauris rhoncus sagittis dolor. Donec sed quam. Vivamus vel diam id massa adipiscing bibendum. Suspendisse potenti. Integer arcu est, adipiscing sit amet, convallis eu, sollicitudin tincidunt, quam. -

    -

    - Etiam ligula lorem, imperdiet ac, luctus eget, ultrices at, odio. Vivamus malesuada, justo eu adipiscing semper, nisi dui tempus magna, quis ultrices nunc tellus id massa. Nullam lobortis auctor sapien. Quisque non nulla. Donec lobortis pellentesque nisl. Sed lacus sapien, viverra vitae, blandit ut, fermentum quis, leo. Morbi augue turpis, hendrerit non, feugiat vel, laoreet sed, est. Nunc velit. Praesent lobortis. Integer enim. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Curabitur faucibus lacus ac ante. Donec odio odio, tincidunt a, egestas nec, scelerisque nec, dui. Cras sollicitudin. Donec lacus enim, mollis sit amet, interdum quis, euismod et, nulla. Nunc sit amet dui eu magna dapibus mollis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nulla facilisi. -

    -

    - In hac habitasse platea dictumst. Nunc neque urna, dapibus ut, tristique ut, bibendum ac, felis. Donec dictum est ut dolor. Etiam accumsan, velit sit amet blandit vestibulum, turpis quam hendrerit risus, vel interdum eros orci in nunc. Curabitur tellus sapien, rutrum ac, euismod ac, malesuada nec, pede. Proin sit amet ipsum. Praesent quam nisl, adipiscing nec, tristique eget, fermentum sed, est. Praesent ac est sit amet orci facilisis placerat. Sed consequat, est sit amet consectetuer viverra, risus urna porttitor tellus, ut convallis nibh libero in lectus. Pellentesque molestie, erat non vehicula pretium, turpis nisi eleifend eros, sed scelerisque tortor odio non tellus. Nunc leo tellus, faucibus vitae, placerat a, accumsan vel, arcu. In et orci. Ut tristique euismod nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Sed nulla nunc, placerat vitae, pellentesque non, interdum non, sapien. Quisque faucibus, eros sed venenatis sagittis, leo risus rhoncus risus, in pretium sem purus a lacus. Aliquam aliquam leo et diam. - -

    -

    - Nulla sagittis diam. Phasellus vitae enim tristique libero molestie tristique. Nam mauris sem, elementum nec, cursus in, fringilla ac, neque. Nunc metus nisi, dictum vel, vulputate quis, porttitor bibendum, tortor. Vestibulum vehicula. Nulla facilisi. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla ac magna sed purus ultricies euismod. Aliquam dictum. Sed mauris. Suspendisse justo. Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Morbi purus lorem, auctor non, porta ac, vehicula vel, orci. Morbi pharetra massa nec leo. Maecenas et mauris. Aliquam porttitor tincidunt nulla. Vestibulum pede. -

    - - -
    -

    Absolute test

    -
    - test image -
    - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -
    - - - - - diff --git a/library/cropper/tests/example-CSS-Float.htm b/library/cropper/tests/example-CSS-Float.htm deleted file mode 100644 index 5066553fe..000000000 --- a/library/cropper/tests/example-CSS-Float.htm +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - CSS - Float test - - - - - - - - - - -

    Test page with floating wrapper

    -

    - Some test content before the image -

    - -
    -

    Float test

    -
    - test image -
    - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -
    - - - - - diff --git a/library/cropper/tests/example-CSS-Relative.htm b/library/cropper/tests/example-CSS-Relative.htm deleted file mode 100644 index 5894fe1f9..000000000 --- a/library/cropper/tests/example-CSS-Relative.htm +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - CSS - Relative test - - - - - - - - - - -

    Test page with relatively positioned wrapper

    -

    - Some test content before the image -

    - -
    -

    Relative test

    -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -
    - - - - - diff --git a/library/cropper/tests/example-CoordsOnLoad.htm b/library/cropper/tests/example-CoordsOnLoad.htm deleted file mode 100644 index 254a23472..000000000 --- a/library/cropper/tests/example-CoordsOnLoad.htm +++ /dev/null @@ -1,108 +0,0 @@ - - - - - - Loading & displaying co-ordinates of crop area on attachment test - - - - - - - - - - -

    Loading & displaying co-ordinates of crop area on attachment test

    -

    - Some test content before the image -

    - -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-CoordsOnLoadWithRatio.htm b/library/cropper/tests/example-CoordsOnLoadWithRatio.htm deleted file mode 100644 index 3a696360a..000000000 --- a/library/cropper/tests/example-CoordsOnLoadWithRatio.htm +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - Loading & displaying co-ordinates (with ratio) of crop area on attachment test< - - - - - - - - - - -

    Loading & displaying co-ordinates (with ratio) of crop area on attachment test

    -

    - Some test content before the image -

    - -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-Dimensions.htm b/library/cropper/tests/example-Dimensions.htm deleted file mode 100644 index f54f99683..000000000 --- a/library/cropper/tests/example-Dimensions.htm +++ /dev/null @@ -1,225 +0,0 @@ - - - - - - Different dimensions test - - - - - - - - - - -

    Multiple dimensions tests

    -

    - Test of applying different dimension restrictions to the cropper -

    - -
    -
    - Set the cropper with the following dimension restrictions: -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - -
    -
    - -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-DynamicImage.htm b/library/cropper/tests/example-DynamicImage.htm deleted file mode 100644 index 898363489..000000000 --- a/library/cropper/tests/example-DynamicImage.htm +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - Dynamic image test - - - - - - - - - - -

    Dynamic image test

    -

    - Test of dynamically changing images or removing & re-applying the cropper -

    - -
    - test image -
    - -

    - - -

    - -

    - - -

    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-FixedRatio.htm b/library/cropper/tests/example-FixedRatio.htm deleted file mode 100644 index 973bedda9..000000000 --- a/library/cropper/tests/example-FixedRatio.htm +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - Fixed ratio test - - - - - - - - - - -

    Fixed ratio test

    -

    - Test of applying a fixed ratio to the cropper -

    -
    - -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-MinimumDimensions.htm b/library/cropper/tests/example-MinimumDimensions.htm deleted file mode 100644 index 3ae93c8e1..000000000 --- a/library/cropper/tests/example-MinimumDimensions.htm +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - Min dimensions test - - - - - - - - - - -

    Minimum (both axes ) dimension test

    -

    - Test of applying a minimum dimension to both axes to the cropper -

    -
    - -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-MinimumWidth.htm b/library/cropper/tests/example-MinimumWidth.htm deleted file mode 100644 index b0576b87f..000000000 --- a/library/cropper/tests/example-MinimumWidth.htm +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - Min (single axis) dimensions test - - - - - - - - - - -

    Minimum (single axis) dimension test

    -

    - Test of applying a minimum dimension to only one axis (width in this case) to the cropper -

    -
    -

    - -
    - test image -
    - - -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    - - - - - diff --git a/library/cropper/tests/example-Preview.htm b/library/cropper/tests/example-Preview.htm deleted file mode 100644 index 701670c91..000000000 --- a/library/cropper/tests/example-Preview.htm +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - -

    - -
    - test image -
    - -
    - -
    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -

    - - -

    -
    - - - - - diff --git a/library/cropper/tests/poppy.jpg b/library/cropper/tests/poppy.jpg deleted file mode 100644 index 1f6498584473b632b707c83ec751499878266915..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18338 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 diff --git a/library/cropper/tests/staticHTMLStructure.htm b/library/cropper/tests/staticHTMLStructure.htm deleted file mode 100644 index ddb99278e..000000000 --- a/library/cropper/tests/staticHTMLStructure.htm +++ /dev/null @@ -1,236 +0,0 @@ - - - - - - - - - - - -

    - - -

    - test image -
    -
    -
    - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -

    Preview:

    -
    - test image -
    -
    - - - - diff --git a/library/cropperjs b/library/cropperjs new file mode 160000 index 000000000..6ac2b895f --- /dev/null +++ b/library/cropperjs @@ -0,0 +1 @@ +Subproject commit 6ac2b895f1630d659f54b31c0900ff2085cf04df diff --git a/view/tpl/cropbody.tpl b/view/tpl/cropbody.tpl index 01d9a24a0..d35546ec6 100755 --- a/view/tpl/cropbody.tpl +++ b/view/tpl/cropbody.tpl @@ -6,36 +6,27 @@ {{$title}}
    -
    +
    diff --git a/view/tpl/cropcover.tpl b/view/tpl/cropcover.tpl index 04b96a603..8888a967a 100755 --- a/view/tpl/cropcover.tpl +++ b/view/tpl/cropcover.tpl @@ -6,36 +6,26 @@ {{$title}}
    -
    +
    diff --git a/view/tpl/crophead.tpl b/view/tpl/crophead.tpl index 48f375426..a5a80c187 100755 --- a/view/tpl/crophead.tpl +++ b/view/tpl/crophead.tpl @@ -1,4 +1,3 @@ - - - - + + + From 1e8dcaffc977be9757b14ad23a4cc9f98c70ae60 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Tue, 23 Jan 2018 16:40:23 -0800 Subject: [PATCH 10/15] cleanup git issue --- library/cropperjs | 1 - 1 file changed, 1 deletion(-) delete mode 160000 library/cropperjs diff --git a/library/cropperjs b/library/cropperjs deleted file mode 160000 index 6ac2b895f..000000000 --- a/library/cropperjs +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6ac2b895f1630d659f54b31c0900ff2085cf04df From 5902528bae21b560b6be4879e5e87ed36ce099b6 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Tue, 23 Jan 2018 16:42:24 -0800 Subject: [PATCH 11/15] undo and redo adding new cropper library as it had a .git config from the original project --- library/cropperjs/.babelrc | 10 + library/cropperjs/.editorconfig | 9 + library/cropperjs/.eslintrc | 13 + library/cropperjs/.travis.yml | 7 + library/cropperjs/CHANGELOG.md | 218 + library/cropperjs/CONTRIBUTING.md | 35 + library/cropperjs/ISSUE_TEMPLATE.md | 21 + library/cropperjs/LICENSE | 21 + library/cropperjs/README.md | 1028 ++ library/cropperjs/dist/cropper.common.js | 3760 +++++++ library/cropperjs/dist/cropper.css | 306 + library/cropperjs/dist/cropper.esm.js | 3758 +++++++ library/cropperjs/dist/cropper.js | 3766 +++++++ library/cropperjs/dist/cropper.min.css | 9 + library/cropperjs/dist/cropper.min.js | 10 + library/cropperjs/docs/css/cropper.css | 306 + library/cropperjs/docs/css/main.css | 252 + library/cropperjs/docs/images/data.jpg | Bin 0 -> 16534 bytes library/cropperjs/docs/images/layers.jpg | Bin 0 -> 26921 bytes library/cropperjs/docs/images/picture-2.jpg | Bin 0 -> 182998 bytes library/cropperjs/docs/images/picture-3.jpg | Bin 0 -> 224777 bytes library/cropperjs/docs/images/picture.jpg | Bin 0 -> 157356 bytes library/cropperjs/docs/index.html | 578 ++ library/cropperjs/docs/js/cropper.js | 3766 +++++++ library/cropperjs/docs/js/main.js | 298 + .../examples/a-range-of-aspect-ratio.html | 71 + .../examples/crop-a-round-image.html | 103 + .../examples/crop-cross-origin-image.html | 49 + .../cropperjs/examples/crop-on-canvas.html | 64 + .../cropperjs/examples/cropper-in-modal.html | 76 + .../cropperjs/examples/customize-preview.html | 123 + .../cropperjs/examples/fixed-crop-box.html | 48 + library/cropperjs/examples/full-crop-box.html | 48 + library/cropperjs/examples/mask-an-image.html | 123 + .../cropperjs/examples/multiple-croppers.html | 48 + .../examples/responsive-container.html | 49 + library/cropperjs/package-lock.json | 9111 +++++++++++++++++ library/cropperjs/package.json | 76 + library/cropperjs/postcss.config.js | 14 + library/cropperjs/rollup.config.js | 50 + library/cropperjs/src/css/cropper.css | 290 + library/cropperjs/src/images/bg.png | Bin 0 -> 168 bytes library/cropperjs/src/js/change.js | 471 + library/cropperjs/src/js/constants.js | 56 + library/cropperjs/src/js/cropper.js | 421 + library/cropperjs/src/js/defaults.js | 99 + library/cropperjs/src/js/events.js | 111 + library/cropperjs/src/js/handlers.js | 212 + library/cropperjs/src/js/methods.js | 842 ++ library/cropperjs/src/js/preview.js | 142 + library/cropperjs/src/js/render.js | 495 + library/cropperjs/src/js/template.js | 27 + library/cropperjs/src/js/utilities.js | 985 ++ library/cropperjs/test/css/main.css | 9 + library/cropperjs/test/events/crop.js | 21 + library/cropperjs/test/events/cropend.js | 24 + library/cropperjs/test/events/cropmove.js | 24 + library/cropperjs/test/events/cropstart.js | 56 + library/cropperjs/test/events/ready.js | 15 + library/cropperjs/test/events/zoom.js | 46 + library/cropperjs/test/index.html | 90 + library/cropperjs/test/js/main.js | 74 + library/cropperjs/test/methods/clear.js | 29 + library/cropperjs/test/methods/crop.js | 24 + library/cropperjs/test/methods/destroy.js | 22 + library/cropperjs/test/methods/disable.js | 60 + library/cropperjs/test/methods/enable.js | 23 + .../cropperjs/test/methods/getCanvasData.js | 23 + .../test/methods/getContainerData.js | 19 + .../cropperjs/test/methods/getCropBoxData.js | 21 + .../test/methods/getCroppedCanvas.js | 33 + library/cropperjs/test/methods/getData.js | 46 + .../cropperjs/test/methods/getImageData.js | 31 + library/cropperjs/test/methods/move.js | 20 + library/cropperjs/test/methods/moveTo.js | 19 + library/cropperjs/test/methods/replace.js | 23 + library/cropperjs/test/methods/reset.js | 35 + library/cropperjs/test/methods/rotate.js | 19 + library/cropperjs/test/methods/rotateTo.js | 20 + library/cropperjs/test/methods/scale.js | 19 + library/cropperjs/test/methods/scaleX.js | 18 + library/cropperjs/test/methods/scaleY.js | 18 + .../cropperjs/test/methods/setAspectRatio.js | 20 + .../cropperjs/test/methods/setCanvasData.js | 34 + .../cropperjs/test/methods/setCropBoxData.js | 36 + library/cropperjs/test/methods/setData.js | 36 + library/cropperjs/test/methods/setDragMode.js | 27 + library/cropperjs/test/methods/zoom.js | 20 + library/cropperjs/test/methods/zoomTo.js | 21 + library/cropperjs/test/options/aspectRatio.js | 39 + library/cropperjs/test/options/autoCrop.js | 39 + library/cropperjs/test/options/background.js | 40 + library/cropperjs/test/options/center.js | 41 + .../test/options/checkCrossOrigin.js | 67 + .../test/options/checkOrientation.js | 43 + library/cropperjs/test/options/crop.js | 21 + .../cropperjs/test/options/cropBoxMovable.js | 41 + .../test/options/cropBoxResizable.js | 65 + library/cropperjs/test/options/cropend.js | 24 + library/cropperjs/test/options/cropmove.js | 24 + library/cropperjs/test/options/cropstart.js | 56 + library/cropperjs/test/options/data.js | 35 + library/cropperjs/test/options/dragMode.js | 60 + library/cropperjs/test/options/guides.js | 43 + library/cropperjs/test/options/highlight.js | 41 + .../cropperjs/test/options/minCanvasHeight.js | 23 + .../cropperjs/test/options/minCanvasWidth.js | 23 + .../test/options/minContainerHeight.js | 21 + .../test/options/minContainerWidth.js | 21 + .../test/options/minCropBoxHeight.js | 23 + .../cropperjs/test/options/minCropBoxWidth.js | 23 + library/cropperjs/test/options/modal.js | 39 + library/cropperjs/test/options/movable.js | 45 + library/cropperjs/test/options/ready.js | 15 + library/cropperjs/test/options/rotatable.js | 39 + library/cropperjs/test/options/scalable.js | 43 + .../test/options/toggleDragModeOnDblclick.js | 45 + library/cropperjs/test/options/viewMode.js | 100 + library/cropperjs/test/options/zoom.js | 46 + library/cropperjs/test/options/zoomOnWheel.js | 47 + library/cropperjs/test/options/zoomable.js | 51 + 121 files changed, 34733 insertions(+) create mode 100644 library/cropperjs/.babelrc create mode 100644 library/cropperjs/.editorconfig create mode 100644 library/cropperjs/.eslintrc create mode 100644 library/cropperjs/.travis.yml create mode 100644 library/cropperjs/CHANGELOG.md create mode 100644 library/cropperjs/CONTRIBUTING.md create mode 100644 library/cropperjs/ISSUE_TEMPLATE.md create mode 100644 library/cropperjs/LICENSE create mode 100644 library/cropperjs/README.md create mode 100644 library/cropperjs/dist/cropper.common.js create mode 100644 library/cropperjs/dist/cropper.css create mode 100644 library/cropperjs/dist/cropper.esm.js create mode 100644 library/cropperjs/dist/cropper.js create mode 100644 library/cropperjs/dist/cropper.min.css create mode 100644 library/cropperjs/dist/cropper.min.js create mode 100644 library/cropperjs/docs/css/cropper.css create mode 100644 library/cropperjs/docs/css/main.css create mode 100644 library/cropperjs/docs/images/data.jpg create mode 100644 library/cropperjs/docs/images/layers.jpg create mode 100644 library/cropperjs/docs/images/picture-2.jpg create mode 100644 library/cropperjs/docs/images/picture-3.jpg create mode 100644 library/cropperjs/docs/images/picture.jpg create mode 100644 library/cropperjs/docs/index.html create mode 100644 library/cropperjs/docs/js/cropper.js create mode 100644 library/cropperjs/docs/js/main.js create mode 100644 library/cropperjs/examples/a-range-of-aspect-ratio.html create mode 100644 library/cropperjs/examples/crop-a-round-image.html create mode 100644 library/cropperjs/examples/crop-cross-origin-image.html create mode 100644 library/cropperjs/examples/crop-on-canvas.html create mode 100644 library/cropperjs/examples/cropper-in-modal.html create mode 100644 library/cropperjs/examples/customize-preview.html create mode 100644 library/cropperjs/examples/fixed-crop-box.html create mode 100644 library/cropperjs/examples/full-crop-box.html create mode 100644 library/cropperjs/examples/mask-an-image.html create mode 100644 library/cropperjs/examples/multiple-croppers.html create mode 100644 library/cropperjs/examples/responsive-container.html create mode 100644 library/cropperjs/package-lock.json create mode 100644 library/cropperjs/package.json create mode 100644 library/cropperjs/postcss.config.js create mode 100644 library/cropperjs/rollup.config.js create mode 100644 library/cropperjs/src/css/cropper.css create mode 100644 library/cropperjs/src/images/bg.png create mode 100644 library/cropperjs/src/js/change.js create mode 100644 library/cropperjs/src/js/constants.js create mode 100644 library/cropperjs/src/js/cropper.js create mode 100644 library/cropperjs/src/js/defaults.js create mode 100644 library/cropperjs/src/js/events.js create mode 100644 library/cropperjs/src/js/handlers.js create mode 100644 library/cropperjs/src/js/methods.js create mode 100644 library/cropperjs/src/js/preview.js create mode 100644 library/cropperjs/src/js/render.js create mode 100644 library/cropperjs/src/js/template.js create mode 100644 library/cropperjs/src/js/utilities.js create mode 100644 library/cropperjs/test/css/main.css create mode 100644 library/cropperjs/test/events/crop.js create mode 100644 library/cropperjs/test/events/cropend.js create mode 100644 library/cropperjs/test/events/cropmove.js create mode 100644 library/cropperjs/test/events/cropstart.js create mode 100644 library/cropperjs/test/events/ready.js create mode 100644 library/cropperjs/test/events/zoom.js create mode 100644 library/cropperjs/test/index.html create mode 100644 library/cropperjs/test/js/main.js create mode 100644 library/cropperjs/test/methods/clear.js create mode 100644 library/cropperjs/test/methods/crop.js create mode 100644 library/cropperjs/test/methods/destroy.js create mode 100644 library/cropperjs/test/methods/disable.js create mode 100644 library/cropperjs/test/methods/enable.js create mode 100644 library/cropperjs/test/methods/getCanvasData.js create mode 100644 library/cropperjs/test/methods/getContainerData.js create mode 100644 library/cropperjs/test/methods/getCropBoxData.js create mode 100644 library/cropperjs/test/methods/getCroppedCanvas.js create mode 100644 library/cropperjs/test/methods/getData.js create mode 100644 library/cropperjs/test/methods/getImageData.js create mode 100644 library/cropperjs/test/methods/move.js create mode 100644 library/cropperjs/test/methods/moveTo.js create mode 100644 library/cropperjs/test/methods/replace.js create mode 100644 library/cropperjs/test/methods/reset.js create mode 100644 library/cropperjs/test/methods/rotate.js create mode 100644 library/cropperjs/test/methods/rotateTo.js create mode 100644 library/cropperjs/test/methods/scale.js create mode 100644 library/cropperjs/test/methods/scaleX.js create mode 100644 library/cropperjs/test/methods/scaleY.js create mode 100644 library/cropperjs/test/methods/setAspectRatio.js create mode 100644 library/cropperjs/test/methods/setCanvasData.js create mode 100644 library/cropperjs/test/methods/setCropBoxData.js create mode 100644 library/cropperjs/test/methods/setData.js create mode 100644 library/cropperjs/test/methods/setDragMode.js create mode 100644 library/cropperjs/test/methods/zoom.js create mode 100644 library/cropperjs/test/methods/zoomTo.js create mode 100644 library/cropperjs/test/options/aspectRatio.js create mode 100644 library/cropperjs/test/options/autoCrop.js create mode 100644 library/cropperjs/test/options/background.js create mode 100644 library/cropperjs/test/options/center.js create mode 100644 library/cropperjs/test/options/checkCrossOrigin.js create mode 100644 library/cropperjs/test/options/checkOrientation.js create mode 100644 library/cropperjs/test/options/crop.js create mode 100644 library/cropperjs/test/options/cropBoxMovable.js create mode 100644 library/cropperjs/test/options/cropBoxResizable.js create mode 100644 library/cropperjs/test/options/cropend.js create mode 100644 library/cropperjs/test/options/cropmove.js create mode 100644 library/cropperjs/test/options/cropstart.js create mode 100644 library/cropperjs/test/options/data.js create mode 100644 library/cropperjs/test/options/dragMode.js create mode 100644 library/cropperjs/test/options/guides.js create mode 100644 library/cropperjs/test/options/highlight.js create mode 100644 library/cropperjs/test/options/minCanvasHeight.js create mode 100644 library/cropperjs/test/options/minCanvasWidth.js create mode 100644 library/cropperjs/test/options/minContainerHeight.js create mode 100644 library/cropperjs/test/options/minContainerWidth.js create mode 100644 library/cropperjs/test/options/minCropBoxHeight.js create mode 100644 library/cropperjs/test/options/minCropBoxWidth.js create mode 100644 library/cropperjs/test/options/modal.js create mode 100644 library/cropperjs/test/options/movable.js create mode 100644 library/cropperjs/test/options/ready.js create mode 100644 library/cropperjs/test/options/rotatable.js create mode 100644 library/cropperjs/test/options/scalable.js create mode 100644 library/cropperjs/test/options/toggleDragModeOnDblclick.js create mode 100644 library/cropperjs/test/options/viewMode.js create mode 100644 library/cropperjs/test/options/zoom.js create mode 100644 library/cropperjs/test/options/zoomOnWheel.js create mode 100644 library/cropperjs/test/options/zoomable.js diff --git a/library/cropperjs/.babelrc b/library/cropperjs/.babelrc new file mode 100644 index 000000000..6909c9dc9 --- /dev/null +++ b/library/cropperjs/.babelrc @@ -0,0 +1,10 @@ +{ + "presets": [ + ["env", { + "modules": false, + "targets": { + "browsers": ["last 2 versions", "ie >= 9"] + } + }] + ] +} diff --git a/library/cropperjs/.editorconfig b/library/cropperjs/.editorconfig new file mode 100644 index 000000000..0f1786729 --- /dev/null +++ b/library/cropperjs/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/library/cropperjs/.eslintrc b/library/cropperjs/.eslintrc new file mode 100644 index 000000000..8757045b6 --- /dev/null +++ b/library/cropperjs/.eslintrc @@ -0,0 +1,13 @@ +{ + "extends": "airbnb-base", + "env": { + "browser": true + }, + "rules": { + "no-param-reassign": "off", + "no-restricted-properties": "off", + "valid-jsdoc": ["error", { + "requireReturn": false + }] + } +} diff --git a/library/cropperjs/.travis.yml b/library/cropperjs/.travis.yml new file mode 100644 index 000000000..de9b4ae30 --- /dev/null +++ b/library/cropperjs/.travis.yml @@ -0,0 +1,7 @@ +language: node_js +node_js: + - "node" +script: + - npm run lint + - npm run build + - npm test diff --git a/library/cropperjs/CHANGELOG.md b/library/cropperjs/CHANGELOG.md new file mode 100644 index 000000000..f0d54cd92 --- /dev/null +++ b/library/cropperjs/CHANGELOG.md @@ -0,0 +1,218 @@ +# Changelog + +## 1.2.2 (Jan 3, 2018) + +- Fix incorrect image natural sizes in iOS Safari (#279). + +## 1.2.1 (Dec 17, 2017) + +- Add `style` field to `package.json`. +- Fix size error when load SVG image (#256). + +## 1.2.0 (Dec 17, 2017) + +- Allow to set the pivot of zoom (#144). +- Fixed a bug of rotation (#260). + +## 1.1.3 (Oct 21, 2017) + +- Fixed a bug of render when disable one of `rotatable` and `scalable` options (#241). + +## 1.1.2 (Oct 18, 2017) + +- Normalize related decimal numbers when crop an image with canvas. + +## 1.1.1 (Oct 11, 2017) + +- Supports to load in node environment (#237). +- Fixed a bug of event binding (#238). + +## 1.1.0 (Oct 8, 2017) + +- Added 4 new options to `getCroppedCanvas` method: `minWidth`, `minHeight`, `maxWidth` and `maxHeight`. +- Enhanced image scaling: the `scaleX` and `scaleY` values should only be `1` or `-1` before, but now they can be any numbers. +- Improved crop box resizing behaviour in the northeast, northwest, southeast and southwest directions. (#222). + +## 1.0.0 (Sep 3, 2017) + +- Fixed a bug of zoom out after cleared the crop box in view mode 1, 2 and 3 (#209). +- Improve crop box resizing behaviour in the east, west, south and north directions (#222). + +## 1.0.0-rc.3 (Jul 7, 2017) + +- Added two new options (`imageSmoothingEnabled` and `imageSmoothingQuality`) to `getCroppedCanvas` method. +- Fixed a bug of RegExp using (#195 by @arusakov). + +## 1.0.0-rc.2 (May 30, 2017) + +- Fixed the issue of canvas box initialization (#179). + +## 1.0.0-rc.1 (Apr 30, 2017) + +- Change the `main` field value from `dist/cropper.js` (UMD) to `dist/cropper.common.js` (CommonJS). +- Added `module` and `browser` fields to `package.json`. + +## 1.0.0-rc (Mar 25, 2017) + +- Fixed the bug of touch zoom (#161). +- Fixed the bug of window resize (#162). +- Improve the `toggleDragModeOnDblclick` option (only available when the `dragMode` option is set to `crop` or `move`) + +## 1.0.0-beta.2 (Feb 25, 2017) + +- Fixed the bug of rotate square image lead image shrink (#155). +- Improved RegExps for DataURL processing (#156). + +## 1.0.0-beta.1 (Jan 21, 2017) + +- Use CSS3 2D Transforms instead of `left` and `top` for better performance (#138). +- Set `withCredentials` attribute when read the image data by XMLHttpRequest (#141). + +## 1.0.0-beta (Jan 1, 2017) + +- Supports to set an element for preview (#113). +- Improved event handler for Pointer Events (#127). + +## 1.0.0-alpha (Dec 4, 2016) + +- Built JavaScript with Rollup. +- Build CSS with PostCSS. +- Fixed a bug of auto crop when replace the image (#83). + +## 0.8.1 (Sep 3, 2016) + +- Fixed the bug of cropping (#80). +- Fixed the bug of calling `ready` event twice when call `replace` method (#81). +- Fixed the bug of `getCroppedCanvas` when set `scalable` or `rotatable` to `false` (#82). + +## 0.8.0 (Aug 18, 2016) + +- Removed `build` event. +- Renamed `built` event to `ready`. +- Fixed the error of orientation transform. +- Ported code to ECMAScript 6. + +## 0.7.2 (Jun 8, 2016) + +- Fixed a bug of `data-*` attributes setting and getting. +- Fixed the calling order of `scale` and `rotate`. + +## 0.7.1 (May 28, 2016) + +- Improved the rotate and scale transform behaviour. +- Improved the `getCroppedCanvas` method (returns the whole canvas if it is not cropped). +- Check cross origin setting when load image by XMLHTTPRequest. + +## 0.7.0 (Mar 20, 2016) + +- Supports 7 custom events: `build`, `built`, `cropstart`, `cropmove`, `cropend`, `crop` and `zoom`. +- The original callback options become shortcuts of these events now. +- IE8 is no longer supported after added these custom events. + +## 0.6.0 (Feb 22, 2016) + +- Added a new parameter to the `replace` method for applying filters. +- Improved the image initializing for Safari. +- Fixed incorrect size limitation of the crop box (#30). +- Fixed incorrect cropped canvas when scaleX or scaleY great than 1. + +## 0.5.6 (Jan 18, 2016) + +- Fixed crossOriginUrl undefined error when exists the `crossOrigin` property. +- Fixed the issue in the "destroy" method (#24). +- Optimized tests. + +## 0.5.5 (Jan 1, 2016) + +- Fixed a dimension bug in the "getCroppedCanvas" method. +- Added an example for cropping round image. + +## 0.5.4 (Dec 28, 2015) + +- Supports to zoom from event triggering point. + +## 0.5.3 (Dec 24, 2015) + +- Limit wheel speed to prevent zoom too fast (#21) +- Improve the `setCropBoxData` method (#22) + +## 0.5.2 (Dec 15, 2015) + +- Fix event handlers + +## 0.5.1 (Dec 12, 2015) + +- Handle Data URL (avoid to use XMLHttpRequest to open a Data URL) +- Handle ajax error when load ArrayBuffer +- Not to transform the image to base64 when Orientation equals to `1` +- Fix some typos + +## 0.5.0 (Dec 5, 2015) + +- Added a new option: `checkOrientation` +- Added a timestamp to the url of preview image + +## 0.4.0 (Dec 2, 2015) + +- Added a new option: `restore` +- Fixed #12: Added vendor prefixes to CSS `transform` + +## 0.3.3 (Nov 30, 2015) + +- Floor the numerical parameters for `CanvasRenderingContext2D.drawImage` + +## 0.3.2 (Nov 18, 2015) + +- Fixed #10: improve new crop box creating + +## 0.3.1 (Nov 11, 2015) + +- Fixed #7: reset the `crossOrigin` when call the `replace` method + +## 0.3.0 (Oct 28, 2015) + +- Supports four view modes +- Supports three drag modes +- Makes the crop box's borders and handlers visible when overflow +- Added some examples +- Fixed some issues + +### Options + +- Added `viewMode` +- Added `dragMode` +- Renamed `touchDragZoom` to `zoomOnTouch` +- Renamed `mouseWheelZoom` to `zoomOnWheel` +- Renamed `doubleClickToggle` to `toggleDragModeOnDblclick` +- Renamed `checkImageOrigin` to `checkCrossOrigin` +- Removed `strict` (supported by `viewMode: 1`) +- Removed `dragCrop` (supported by `dragMode: 'crop'`) + +## 0.2.1 (Oct 28, 2015) + +- Fix the error jQuery reference on the `setCanvasData` method +- Fix typo on the `destroy` method + +## 0.2.0 (Oct 25, 2015) + +- Added 5 new methods: `moveTo`, `zoomTo`, `rotateTo`, `scaleX` and `scaleY` +- Improved 4 methods: `move`, `zoom`, `rotate` and `getCanvasData` +- Improved cropping + +## 0.1.1 (Oct 10, 2015) + +- Improved canvas limitation +- Improved crop box limitation +- Improved preview for cross origin image + +## 0.1.0 (Sep 25, 2015) + +- Supports touch (mobile) +- Supports zoom +- Supports rotation +- Supports scale (flip) +- Supports canvas +- Supports multiple croppers +- Cross-browser support +- Supports 37 options: `aspectRatio`, `data`, `preview`, `strict`, `responsive`, `checkImageOrigin`, `modal`, `guides`, `center`, `highlight`, `background`, `autoCrop`, `autoCropArea`, `dragCrop`, `movable`, `rotatable`, `scalable`, `zoomable`, `mouseWheelZoom`, `wheelZoomRatio`, `touchDragZoom`, `cropBoxMovable`, `cropBoxResizable`, `doubleClickToggle`, `minCanvasWidth`, `minCanvasHeight`, `minCropBoxWidth`, `minCropBoxHeight`, `minContainerWidth`, `minContainerHeight`, `build`, `built`, `cropstart`, `cropmove`, `cropend`, `crop`, `zoom`. +- Support 22 methods: `crop`, `reset`, `clear`, `replace`, `enable`, `disable`, `destroy`, `move`, `zoom`, `rotate`, `scale`, `getData`, `setData`, `getContainerData`, `getImageData`, `getCanvasData`, `setCanvasData`, `getCropBoxData`, `setCropBoxData`, `getCroppedCanvas`, `setAspectRatio`, `setDragMode`. diff --git a/library/cropperjs/CONTRIBUTING.md b/library/cropperjs/CONTRIBUTING.md new file mode 100644 index 000000000..7c31d7ab0 --- /dev/null +++ b/library/cropperjs/CONTRIBUTING.md @@ -0,0 +1,35 @@ +# Contributing to Cropper + +## How to report bugs + +### Make sure it is a Cropper bug + +Most bugs reported to our bug tracker are actually bugs in user code, not in Cropper code. Keep in mind that just because your code throws an error inside of Cropper, this does *not* mean the bug is a Cropper bug. + +Ask for help first in a discussion forum like [Stack Overflow](http://stackoverflow.com/). You will get much quicker support, and you will help avoid tying up the Cropper team with invalid bug reports. + +### Disable browser extensions + +Make sure you have reproduced the bug with all browser extensions and add-ons disabled, as these can sometimes cause things to break in interesting and unpredictable ways. Try using incognito, stealth or anonymous browsing modes. + +### Try the latest version of Cropper + +Bugs in old versions of Cropper may have already been fixed. In order to avoid reporting known issues, make sure you are always testing against the [latest release](https://github.com/fengyuanchen/cropperjs/releases/latest). We cannot fix bugs in older released files, if a bug has been fixed in a subsequent version of Cropper the site should upgrade. + +### Simplify the test case + +When experiencing a problem, [reduce your code](http://webkit.org/quality/reduction.html) to the bare minimum required to reproduce the issue. This makes it *much* easier to isolate and fix the offending code. Bugs reported without reduced test cases take on average 9001% longer to fix than bugs that are submitted with them, so you really should try to do this if at all possible. + +### Search for related or duplicate issues + +Go to the [Cropper issue tracker](https://github.com/fengyuanchen/cropperjs/issues) and make sure the problem hasn't already been reported. If not, create a new issue there and include your test case. + +### Browser support + +Remember that Cropper supports multiple browsers and their versions; any contributed code must work in all of them. You can refer to the [browser support page](https://github.com/fengyuanchen/cropperjs/blob/master/README.md#browser-support) for the current list of supported browsers. + +## Notes for pull request + +- Run the test suites in the `test` directory first. +- Don't modify any files in the `dist` directory. +- Follow the same code style as the library. diff --git a/library/cropperjs/ISSUE_TEMPLATE.md b/library/cropperjs/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..0ed98b61d --- /dev/null +++ b/library/cropperjs/ISSUE_TEMPLATE.md @@ -0,0 +1,21 @@ +Before opening an issue: + +- [Search for duplicate or closed issues](https://github.com/fengyuanchen/cropperjs/issues?utf8=%E2%9C%93&q=is%3Aissue) +- Prepare a [reduced test case](https://css-tricks.com/reduced-test-cases/) for any bugs +- Read the [contributing guidelines](https://github.com/fengyuanchen/cropperjs/blob/master/CONTRIBUTING.md) + +When asking general "how to" questions: + +- Please do not open an issue here +- Instead, ask for help on [StackOverflow](http://stackoverflow.com/) + +When reporting a bug, include: + +- Operating system and version (Windows, Mac OS X, Android, iOS, Win10 Mobile) +- Browser and version (Chrome, Firefox, Safari, IE, MS Edge, Opera 15+, Android Browser) +- Reduced test cases and potential fixes using [JS Bin](https://jsbin.com), [JSFiddle](https://jsfiddle.net/) or [CodePen](https://codepen.io/) + +When suggesting a feature, include: + +- As much detail as possible for what we should add and why it's important to Cropper.js +- Relevant links to prior art, screenshots, or live demos whenever possible diff --git a/library/cropperjs/LICENSE b/library/cropperjs/LICENSE new file mode 100644 index 000000000..e9b8a22b3 --- /dev/null +++ b/library/cropperjs/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015-present Chen Fengyuan + +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. diff --git a/library/cropperjs/README.md b/library/cropperjs/README.md new file mode 100644 index 000000000..73e8dda30 --- /dev/null +++ b/library/cropperjs/README.md @@ -0,0 +1,1028 @@ +# Cropper.js + +[![Build Status](https://travis-ci.org/fengyuanchen/cropperjs.svg)](https://travis-ci.org/fengyuanchen/cropperjs) [![Downloads](https://img.shields.io/npm/dm/cropperjs.svg)](https://www.npmjs.com/package/cropperjs) [![Version](https://img.shields.io/npm/v/cropperjs.svg)](https://www.npmjs.com/package/cropperjs) + +> JavaScript image cropper. + +- [Website](https://fengyuanchen.github.io/cropperjs) +- [Photo Editor](https://fengyuanchen.github.io/photo-editor) - An advanced example of Cropper.js. + +## Table of contents + +- [Features](#features) +- [Main](#main) +- [Getting started](#getting-started) +- [Options](#options) +- [Methods](#methods) +- [Events](#events) +- [No conflict](#no-conflict) +- [Browser support](#browser-support) +- [Contributing](#contributing) +- [Versioning](#versioning) +- [License](#license) + +## Features + +- Supports 38 [options](#options) +- Supports 27 [methods](#methods) +- Supports 6 [events](#events) +- Supports touch (mobile) +- Supports zooming +- Supports rotating +- Supports scaling (flipping) +- Supports multiple croppers +- Supports to crop on a canvas +- Supports to crop image in the browser-side by canvas +- Supports to translate Exif Orientation information +- Cross-browser support + +## Main + +```text +dist/ +├── cropper.css +├── cropper.min.css (compressed) +├── cropper.js (UMD) +├── cropper.min.js (UMD, compressed) +├── cropper.common.js (CommonJS, default) +└── cropper.esm.js (ES Module) +``` + +## Getting started + +### Installation + +```shell +npm install cropperjs +``` + +Include files: + +```html + + +``` + +The [cdnjs](https://github.com/cdnjs/cdnjs) provides CDN support for Cropper.js's CSS and JavaScript. You can find the links [here](https://cdnjs.com/libraries/cropperjs). + +### Usage + +Initialize with `Cropper` constructor: + +- Browser: `window.Cropper` +- CommonJS: `var Cropper = require('cropperjs')` +- ES2015: `import Cropper from 'cropperjs'` + +```html + +
    + +
    +``` + +```css +/* Limit image width to avoid overflow the container */ +img { + max-width: 100%; /* This rule is very important, please do not ignore this! */ +} +``` + +```js +var image = document.getElementById('image'); +var cropper = new Cropper(image, { + aspectRatio: 16 / 9, + crop: function(e) { + console.log(e.detail.x); + console.log(e.detail.y); + console.log(e.detail.width); + console.log(e.detail.height); + console.log(e.detail.rotate); + console.log(e.detail.scaleX); + console.log(e.detail.scaleY); + } +}); +``` + +#### FAQ + +How to crop a new area after zoom in or zoom out? + +> Just double click your mouse to enter crop mode. + +How to move the image after crop an area? + +> Just double click your mouse to enter move mode. + +How to fix aspect ratio in free ratio mode? + +> Just hold the `shift` key when you resize the crop box. + +How to crop a square area in free ratio mode? + +> Just hold the `shift` key when you crop on the image. + +#### Notes + +- The size of the cropper inherits from the size of the image's parent element (wrapper), so be sure to wrap the image with a **visible block element**. + > If you are using cropper in a modal, you should initialize the cropper after the modal shown completely. Otherwise, you will not get a correct cropper. + +- The outputted cropped data bases on the original image size, so you can use them to crop the image directly. + +- If you try to start cropper on a cross-origin image, please make sure that your browser supports HTML5 [CORS settings attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes), and your image server supports the `Access-Control-Allow-Origin` option (see the [HTTP access control (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS)). + +#### Known issues + +- [Known iOS resource limits](https://developer.apple.com/library/mac/documentation/AppleApplications/Reference/SafariWebContent/CreatingContentforSafarioniPhone/CreatingContentforSafarioniPhone.html): As iOS devices limit memory, the browser may crash when you are cropping a large image (iPhone camera resolution). To avoid this, you may resize the image first (preferably below 1024 pixels) before start a cropper. + +- Known image size increase: When export the cropped image on browser-side with the `HTMLCanvasElement.toDataURL` method, the size of the exported image may be greater than the original image's. This is because the type of the exported image is not the same as the original image's. So just pass the type the original image's as the first parameter to `toDataURL` to fix this. For example, if the original type is JPEG, then use `cropper.getCroppedCanvas().toDataURL('image/jpeg')` to export image. + +[⬆ back to top](#table-of-contents) + +## Options + +You may set cropper options with `new Cropper(image, options)`. +If you want to change the global default options, You may use `Cropper.setDefaults(options)`. + +### viewMode + +- Type: `Number` +- Default: `0` +- Options: + - `0`: no restrictions + - `1`: restrict the crop box to not exceed the size of the canvas. + - `2`: restrict the minimum canvas size to fit within the container. If the proportions of the the canvas and the container differ, the minimum canvas will be surrounded by extra space in one of the dimensions. + - `3`: restrict the minimum canvas size to fill fit the container. If the proportions of the canvas and the container are different, the container will not be able to fit the whole canvas in one of the dimensions. + +Define the view mode of the cropper. If you set `viewMode` to `0`, the crop box can extend outside the canvas, while a value of `1`, `2` or `3` will restrict the crop box to the size of the canvas. A `viewMode` of `2` or `3` will additionally restrict the canvas to the container. Note that if the proportions of the canvas and the container are the same, there is no difference between `2` and `3`. + +### dragMode + +- Type: `String` +- Default: `'crop'` +- Options: + - `'crop'`: create a new crop box + - `'move'`: move the canvas + - `'none'`: do nothing + +Define the dragging mode of the cropper. + +### aspectRatio + +- Type: `Number` +- Default: `NaN` + +Set the aspect ratio of the crop box. By default, the crop box is free ratio. + +### data + +- Type: `Object` +- Default: `null` + +The previous cropped data if you had stored, will be passed to `setData` method automatically when built. + +### preview + +- Type: `Element` or `String` +- Default: `''` +- An element or A valid selector for [Document.querySelectorAll](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll) + +Add extra elements (containers) for previewing. + +**Notes:** + +- The maximum width is the initial width of preview container. +- The maximum height is the initial height of preview container. +- If you set an `aspectRatio` option, be sure to set the same aspect ratio to the preview container. +- If preview is not getting properly displayed, set `overflow: hidden` style to the preview container. + +### responsive + +- Type: `Boolean` +- Default: `true` + +Re-render the cropper when resize the window. + +### restore + +- Type: `Boolean` +- Default: `true` + +Restore the cropped area after resize the window. + +### checkCrossOrigin + +- Type: `Boolean` +- Default: `true` + +Check if the current image is a cross-origin image. + +If it is, when clone the image, a `crossOrigin` attribute will be added to the cloned image element and a timestamp will be added to the `src` attribute to reload the source image to avoid browser cache error. + +By adding `crossOrigin` attribute to image will stop adding timestamp to image url and stop reload of image, but the request (XMLHttpRequest) to read the image data for orientation checking will require a timestamp now. + +If the value of the image's `crossOrigin` attribute is `"use-credentials"`, then the `withCredentials` attribute will set to `true` when read the image data by XMLHttpRequest. + +### checkOrientation + +- Type: `Boolean` +- Default: `true` + +Check the current image's Exif Orientation information. + +More exactly, read the Orientation value for rotating or flipping the image, and then override the Orientation value with `1` (the default value) to avoid some issues ([1](https://github.com/fengyuanchen/cropper/issues/120), [2](https://github.com/fengyuanchen/cropper/issues/509)) on iOS devices. + +Requires to set both the `rotatable` and `scalable` options to `true` at the same time. + +**Note:** Don't trust this all the time as some JPG images have incorrect (not standard) Orientation values. + +> Requires [Typed Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) support ([IE 10+](http://caniuse.com/typedarrays)). + +### modal + +- Type: `Boolean` +- Default: `true` + +Show the black modal above the image and under the crop box. + +### guides + +- Type: `Boolean` +- Default: `true` + +Show the dashed lines above the crop box. + +### center + +- Type: `Boolean` +- Default: `true` + +Show the center indicator above the crop box. + +### highlight + +- Type: `Boolean` +- Default: `true` + +Show the white modal above the crop box (highlight the crop box). + +### background + +- Type: `Boolean` +- Default: `true` + +Show the grid background of the container. + +### autoCrop + +- Type: `Boolean` +- Default: `true` + +Enable to crop the image automatically when initialize. + +### autoCropArea + +- Type: `Number` +- Default: `0.8` (80% of the image) + +A number between 0 and 1. Define the automatic cropping area size (percentage). + +### movable + +- Type: `Boolean` +- Default: `true` + +Enable to move the image. + +### rotatable + +- Type: `Boolean` +- Default: `true` + +Enable to rotate the image. + +### scalable + +- Type: `Boolean` +- Default: `true` + +Enable to scale the image. + +### zoomable + +- Type: `Boolean` +- Default: `true` + +Enable to zoom the image. + +### zoomOnTouch + +- Type: `Boolean` +- Default: `true` + +Enable to zoom the image by dragging touch. + +### zoomOnWheel + +- Type: `Boolean` +- Default: `true` + +Enable to zoom the image by wheeling mouse. + +### wheelZoomRatio + +- Type: `Number` +- Default: `0.1` + +Define zoom ratio when zoom the image by wheeling mouse. + +### cropBoxMovable + +- Type: `Boolean` +- Default: `true` + +Enable to move the crop box by dragging. + +### cropBoxResizable + +- Type: `Boolean` +- Default: `true` + +Enable to resize the crop box by dragging. + +### toggleDragModeOnDblclick + +- Type: `Boolean` +- Default: `true` + +Enable to toggle drag mode between "crop" and "move" when click twice on the cropper. + +### minContainerWidth + +- Type: `Number` +- Default: `200` + +The minimum width of the container. + +### minContainerHeight + +- Type: `Number` +- Default: `100` + +The minimum height of the container. + +### minCanvasWidth + +- Type: `Number` +- Default: `0` + +The minimum width of the canvas (image wrapper). + +### minCanvasHeight + +- Type: `Number` +- Default: `0` + +The minimum height of the canvas (image wrapper). + +### minCropBoxWidth + +- Type: `Number` +- Default: `0` + +The minimum width of the crop box. + +**Note:** This size is relative to the page, not the image. + +### minCropBoxHeight + +- Type: `Number` +- Default: `0` + +The minimum height of the crop box. + +**Note:** This size is relative to the page, not the image. + +### ready + +- Type: `Function` +- Default: `null` + +A shortcut of the "ready" event. + +### cropstart + +- Type: `Function` +- Default: `null` + +A shortcut of the "cropstart" event. + +### cropmove + +- Type: `Function` +- Default: `null` + +A shortcut of the "cropmove" event. + +### cropend + +- Type: `Function` +- Default: `null` + +A shortcut of the "cropend" event. + +### crop + +- Type: `Function` +- Default: `null` + +A shortcut of the "crop" event. + +### zoom + +- Type: `Function` +- Default: `null` + +A shortcut of the "zoom" event. + +[⬆ back to top](#table-of-contents) + +## Methods + +As there is an **asynchronous** process when load the image, you **should call most of the methods after ready**, except "setAspectRatio", "replace" and "destroy". + +> If a method doesn't need to return any value, it will return the cropper instance (`this`) for chain composition. + +```js +new Cropper(image, { + ready: function () { + // this.cropper[method](argument1, , argument2, ..., argumentN); + this.cropper.move(1, -1); + + // Allows chain composition + this.cropper.move(1, -1).rotate(45).scale(1, -1); + } +}); +``` + +### crop() + +Show the crop box manually. + +```js +new Cropper(image, { + autoCrop: false, + ready: function () { + // Do something here + // ... + + // And then + this.cropper.crop(); + } +}); +``` + +### reset() + +Reset the image and crop box to their initial states. + +### clear() + +Clear the crop box. + +### replace(url[, onlyColorChanged]) + +- **url**: + - Type: `String` + - A new image url. + +- **onlyColorChanged** (optional): + - Type: `Boolean` + - If only change the color, not the size, then the cropper only need to change the srcs of all related images, not need to rebuild the cropper. This can be used for applying filters. + - If not present, its default value is `false`. + +Replace the image's src and rebuild the cropper. + +### enable() + +Enable (unfreeze) the cropper. + +### disable() + +Disable (freeze) the cropper. + +### destroy() + +Destroy the cropper and remove the instance from the image. + +### move(offsetX[, offsetY]) + +- **offsetX**: + - Type: `Number` + - Moving size (px) in the horizontal direction. + +- **offsetY** (optional): + - Type: `Number` + - Moving size (px) in the vertical direction. + - If not present, its default value is `offsetX`. + +Move the canvas (image wrapper) with relative offsets. + +```js +cropper.move(1); +cropper.move(1, 0); +cropper.move(0, -1); +``` + +### moveTo(x[, y]) + +- **x**: + - Type: `Number` + - The `left` value of the canvas + +- **y** (optional): + - Type: `Number` + - The `top` value of the canvas + - If not present, its default value is `x`. + +Move the canvas (image wrapper) to an absolute point. + +### zoom(ratio) + +- **ratio**: + - Type: `Number` + - Zoom in: requires a positive number (ratio > 0) + - Zoom out: requires a negative number (ratio < 0) + +Zoom the canvas (image wrapper) with a relative ratio. + +```js +cropper.zoom(0.1); +cropper.zoom(-0.1); +``` + +### zoomTo(ratio[, pivot]) + +- **ratio**: + - Type: `Number` + - Requires a positive number (ratio > 0) + +- **pivot** (optional): + - Type: `Object` + - Schema: `{ x: Number, y: Number }` + - The coordinate of the center point for zooming, base on the top left corner of the cropper container. + +Zoom the canvas (image wrapper) to an absolute ratio. + +```js +cropper.zoomTo(1); // 1:1 (canvasData.width === canvasData.naturalWidth) + +const containerData = cropper.getContainerData(); + +// Zoom to 50% from the center of the container. +cropper.zoomTo(.5, { + x: containerData.width / 2, + y: containerData.height / 2, +}); +``` + +### rotate(degree) + +- **degree**: + - Type: `Number` + - Rotate right: requires a positive number (degree > 0) + - Rotate left: requires a negative number (degree < 0) + +Rotate the image with a relative degree. + +> Requires [CSS3 2D Transforms](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) support ([IE 9+](http://caniuse.com/transforms2d)). + +```js +cropper.rotate(90); +cropper.rotate(-90); +``` + +### rotateTo(degree) + +- **degree**: + - Type: `Number` + +Rotate the image to an absolute degree. + +### scale(scaleX[, scaleY]) + +- **scaleX**: + - Type: `Number` + - Default: `1` + - The scaling factor to apply on the abscissa of the image. + - When equal to `1` it does nothing. + +- **scaleY** (optional): + - Type: `Number` + - The scaling factor to apply on the ordinate of the image. + - If not present, its default value is `scaleX`. + +Scale the image. + +> Requires [CSS3 2D Transforms](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) support ([IE 9+](http://caniuse.com/transforms2d)). + +```js +cropper.scale(-1); // Flip both horizontal and vertical +cropper.scale(-1, 1); // Flip horizontal +cropper.scale(1, -1); // Flip vertical +``` + +### scaleX(scaleX) + +- **scaleX**: + - Type: `Number` + - Default: `1` + - The scaling factor to apply on the abscissa of the image. + - When equal to `1` it does nothing. + +Scale the abscissa of the image. + +### scaleY(scaleY) + +- **scaleY**: + - Type: `Number` + - Default: `1` + - The scaling factor to apply on the ordinate of the image. + - When equal to `1` it does nothing. + +Scale the ordinate of the image. + +### getData([rounded]) + +- **rounded** (optional): + - Type: `Boolean` + - Default: `false` + - Set `true` to get rounded values. + +- (return value): + - Type: `Object` + - Properties: + - `x`: the offset left of the cropped area + - `y`: the offset top of the cropped area + - `width`: the width of the cropped area + - `height`: the height of the cropped area + - `rotate`: the rotated degrees of the image + - `scaleX`: the scaling factor to apply on the abscissa of the image + - `scaleY`: the scaling factor to apply on the ordinate of the image + +Output the final cropped area position and size data (base on the natural size of the original image). + +> You can send the data to server-side to crop the image directly: +> 1. Rotate the image with the `rotate` property. +> 1. Scale the image with the `scaleX` and `scaleY` properties. +> 1. Crop the image with the `x`, `y`, `width` and `height` properties. + +![A schematic diagram for data's properties](docs/images/data.jpg) + +### setData(data) + +- **data**: + - Type: `Object` + - Properties: See the [`getData`](#getdatarounded) method. + - You may need to round the data properties before passing them in. + +Change the cropped area position and size with new data (base on the original image). + +> **Note:** This method only available when the `viewMode` option great than or equal to `1`. + +### getContainerData() + +- (return value): + - Type: `Object` + - Properties: + - `width`: the current width of the container + - `height`: the current height of the container + +Output the container size data. + +![A schematic diagram for cropper's layers](docs/images/layers.jpg) + +### getImageData() + +- (return value): + - Type: `Object` + - Properties: + - `left`: the offset left of the image + - `top`: the offset top of the image + - `width`: the width of the image + - `height`: the height of the image + - `naturalWidth`: the natural width of the image + - `naturalHeight`: the natural height of the image + - `aspectRatio`: the aspect ratio of the image + - `rotate`: the rotated degrees of the image if rotated + - `scaleX`: the scaling factor to apply on the abscissa of the image if scaled + - `scaleY`: the scaling factor to apply on the ordinate of the image if scaled + +Output the image position, size and other related data. + +### getCanvasData() + +- (return value): + - Type: `Object` + - Properties: + - `left`: the offset left of the canvas + - `top`: the offset top of the canvas + - `width`: the width of the canvas + - `height`: the height of the canvas + - `naturalWidth`: the natural width of the canvas (read only) + - `naturalHeight`: the natural height of the canvas (read only) + +Output the canvas (image wrapper) position and size data. + +```js +var imageData = cropper.getImageData(); +var canvasData = cropper.getCanvasData(); + +if (imageData.rotate % 180 === 0) { + console.log(canvasData.naturalWidth === imageData.naturalWidth); // true +} +``` + +### setCanvasData(data) + +- **data**: + - Type: `Object` + - Properties: + - `left`: the new offset left of the canvas + - `top`: the new offset top of the canvas + - `width`: the new width of the canvas + - `height`: the new height of the canvas + +Change the canvas (image wrapper) position and size with new data. + +### getCropBoxData() + +- (return value): + - Type: `Object` + - Properties: + - `left`: the offset left of the crop box + - `top`: the offset top of the crop box + - `width`: the width of the crop box + - `height`: the height of the crop box + +Output the crop box position and size data. + +### setCropBoxData(data) + +- **data**: + - Type: `Object` + - Properties: + - `left`: the new offset left of the crop box + - `top`: the new offset top of the crop box + - `width`: the new width of the crop box + - `height`: the new height of the crop box + +Change the crop box position and size with new data. + +### getCroppedCanvas([options]) + +- **options** (optional): + - Type: `Object` + - Properties: + - `width`: the destination width of the output canvas. + - `height`: the destination height of the output canvas. + - `minWidth`: the minimum destination width of the output canvas, the default value is `0`. + - `minHeight`: the minimum destination height of the output canvas, the default value is `0`. + - `maxWidth`: the maximum destination width of the output canvas, the default value is `Infinity`. + - `maxHeight`: the maximum destination height of the output canvas, the default value is `Infinity`. + - `fillColor`: a color to fill any alpha values in the output canvas, the default value is `transparent`. + - [`imageSmoothingEnabled`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled): set to change if images are smoothed (`true`, default) or not (`false`). + - [`imageSmoothingQuality`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality): set the quality of image smoothing, one of "low" (default), "medium", or "high". + +- (return value): + - Type: `HTMLCanvasElement` + - A canvas drawn the cropped image. + +- Notes: + - The aspect ratio of the output canvas will be fitted to aspect ratio of the crop box automatically. + - If you intend to get a JPEG image from the output canvas, you should set the `fillColor` option first, if not, the transparent part in the JPEG image will become black by default. + +- Browser support: + - Basic image: requires [Canvas](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement) support ([IE 9+](http://caniuse.com/canvas)). + - Rotated image: requires [CSS3 2D Transforms](https://developer.mozilla.org/en-US/docs/Web/CSS/transform) support ([IE 9+](http://caniuse.com/transforms2d)). + - Cross-origin image: requires HTML5 [CORS settings attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) support ([IE 11+](http://caniuse.com/cors)). + +Get a canvas drawn the cropped image. If it is not cropped, then returns a canvas drawn the whole image. + +> After then, you can display the canvas as an image directly, or use [HTMLCanvasElement.toDataURL](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) to get a Data URL, or use [HTMLCanvasElement.toBlob](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob) to get a blob and upload it to server with [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) if the browser supports these APIs. + +Avoid to get a blank output image, you might need to set the `maxWidth` and `maxHeight` properties to limited numbers, because of [the size limits of a canvas element](https://stackoverflow.com/questions/6081483/maximum-size-of-a-canvas-element). + +```js +cropper.getCroppedCanvas(); + +cropper.getCroppedCanvas({ + width: 160, + height: 90, + minWidth: 256, + minHeight: 256, + maxWidth: 4096, + maxHeight: 4096, + fillColor: '#fff', + imageSmoothingEnabled: false, + imageSmoothingQuality: 'high', +}); + +// Upload cropped image to server if the browser supports `HTMLCanvasElement.toBlob` +cropper.getCroppedCanvas().toBlob(function (blob) { + var formData = new FormData(); + + formData.append('croppedImage', blob); + + // Use `jQuery.ajax` method + $.ajax('/path/to/upload', { + method: "POST", + data: formData, + processData: false, + contentType: false, + success: function () { + console.log('Upload success'); + }, + error: function () { + console.log('Upload error'); + } + }); +}); +``` + +### setAspectRatio(aspectRatio) + +- **aspectRatio**: + - Type: `Number` + - Requires a positive number. + +Change the aspect ratio of the crop box. + +### setDragMode([mode]) + +- **mode** (optional): + - Type: `String` + - Default: `'none'` + - Options: `'none'`, `'crop'`, `'move'` + +Change the drag mode. + +**Tips:** You can toggle the "crop" and "move" mode by double click on the cropper. + +[⬆ back to top](#table-of-contents) + +## Events + +### ready + +This event fires when the target image has been loaded and the cropper instance is ready for cropping. + +```js +var cropper; + +image.addEventListener('ready', function () { + console.log(this.cropper === cropper); + // -> true +}); + +cropper = new Cropper(image); +``` + +### cropstart + +- **event.detail.originalEvent**: + - Type: `Event` + - Options: `mousedown`, `touchstart` and `pointerdown` + +- **event.detail.action**: + - Type: `String` + - Options: + - `'crop'`: create a new crop box + - `'move'`: move the canvas (image wrapper) + - `'zoom'`: zoom in / out the canvas (image wrapper) by touch. + - `'e'`: resize the east side of the crop box + - `'w'`: resize the west side of the crop box + - `'s'`: resize the south side of the crop box + - `'n'`: resize the north side of the crop box + - `'se'`: resize the southeast side of the crop box + - `'sw'`: resize the southwest side of the crop box + - `'ne'`: resize the northeast side of the crop box + - `'nw'`: resize the northwest side of the crop box + - `'all'`: move the crop box (all directions) + +This event fires when the canvas (image wrapper) or the crop box starts to change. + +```js +image.addEventListener('cropstart', function (e) { + console.log(e.detail.originalEvent); + console.log(e.detail.action); +}); +``` + +### cropmove + +- **event.detail.originalEvent**: + - Type: `Event` + - Options: `mousemove`, `touchmove` and `pointermove`. + +- **event.detail.action**: the same as "cropstart". + +This event fires when the canvas (image wrapper) or the crop box is changing. + +### cropend + +- **event.detail.originalEvent**: + - Type: `Event` + - Options: `mouseup`, `touchend`, `touchcancel`, `pointerup` and `pointercancel`. + +- **event.detail.action**: the same as "cropstart". + +This event fires when the canvas (image wrapper) or the crop box stops to change. + +### crop + +- **event.detail.x** +- **event.detail.y** +- **event.detail.width** +- **event.detail.height** +- **event.detail.rotate** +- **event.detail.scaleX** +- **event.detail.scaleY** + +> About these properties, see the [`getData`](#getdatarounded) method. + +This event fires when the canvas (image wrapper) or the crop box changed. + +### zoom + +- **event.detail.originalEvent**: + - Type: `Event` + - Options: `wheel`, `touchmove`. + +- **event.detail.oldRatio**: + - Type: `Number` + - The old (current) ratio of the canvas + +- **event.detail.ratio**: + - Type: `Number` + - The new (next) ratio of the canvas (`canvasData.width / canvasData.naturalWidth`) + +This event fires when a cropper instance starts to zoom in or zoom out its canvas (image wrapper). + +```js +image.addEventListener('zoom', function (e) { + + // Zoom in + if (e.detail.ratio > e.detail.oldRatio) { + e.preventDefault(); // Prevent zoom in + } + + // Zoom out + // ... +}); +``` + +[⬆ back to top](#table-of-contents) + +## No conflict + +If you have to use other cropper with the same namespace, just call the `Cropper.noConflict` static method to revert to it. + +```html + + + +``` + +## Browser support + +- Chrome (latest) +- Firefox (latest) +- Safari (latest) +- Opera (latest) +- Edge (latest) +- Internet Explorer 9+ + +## Contributing + +Please read through our [contributing guidelines](CONTRIBUTING.md). + +## Versioning + +Maintained under the [Semantic Versioning guidelines](http://semver.org/). + +## License + +[MIT](http://opensource.org/licenses/MIT) © [Chen Fengyuan](http://chenfengyuan.com) + +## Related projects + +- [angular-cropperjs](https://github.com/matheusdavidson/angular-cropperjs) by @matheusdavidson +- [ember-cropperjs](https://github.com/danielthall/ember-cropperjs) by @danielthall +- [iron-cropper](https://www.webcomponents.org/element/safetychanger/iron-cropper) (web component) by @safetychanger +- [react-cropper](https://github.com/roadmanfong/react-cropper) by @roadmanfong +- [vue-cropperjs](https://github.com/Agontuk/vue-cropperjs) by @Agontuk + +[⬆ back to top](#table-of-contents) diff --git a/library/cropperjs/dist/cropper.common.js b/library/cropperjs/dist/cropper.common.js new file mode 100644 index 000000000..38c62e824 --- /dev/null +++ b/library/cropperjs/dist/cropper.common.js @@ -0,0 +1,3760 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:27:18.062Z + */ + +'use strict'; + +var WINDOW = typeof window !== 'undefined' ? window : {}; +var NAMESPACE = 'cropper'; + +// Actions +var ACTION_ALL = 'all'; +var ACTION_CROP = 'crop'; +var ACTION_MOVE = 'move'; +var ACTION_ZOOM = 'zoom'; +var ACTION_EAST = 'e'; +var ACTION_WEST = 'w'; +var ACTION_SOUTH = 's'; +var ACTION_NORTH = 'n'; +var ACTION_NORTH_EAST = 'ne'; +var ACTION_NORTH_WEST = 'nw'; +var ACTION_SOUTH_EAST = 'se'; +var ACTION_SOUTH_WEST = 'sw'; + +// Classes +var CLASS_CROP = NAMESPACE + '-crop'; +var CLASS_DISABLED = NAMESPACE + '-disabled'; +var CLASS_HIDDEN = NAMESPACE + '-hidden'; +var CLASS_HIDE = NAMESPACE + '-hide'; +var CLASS_INVISIBLE = NAMESPACE + '-invisible'; +var CLASS_MODAL = NAMESPACE + '-modal'; +var CLASS_MOVE = NAMESPACE + '-move'; + +// Data keys +var DATA_ACTION = 'action'; +var DATA_PREVIEW = 'preview'; + +// Drag modes +var DRAG_MODE_CROP = 'crop'; +var DRAG_MODE_MOVE = 'move'; +var DRAG_MODE_NONE = 'none'; + +// Events +var EVENT_CROP = 'crop'; +var EVENT_CROP_END = 'cropend'; +var EVENT_CROP_MOVE = 'cropmove'; +var EVENT_CROP_START = 'cropstart'; +var EVENT_DBLCLICK = 'dblclick'; +var EVENT_ERROR = 'error'; +var EVENT_LOAD = 'load'; +var EVENT_POINTER_DOWN = WINDOW.PointerEvent ? 'pointerdown' : 'touchstart mousedown'; +var EVENT_POINTER_MOVE = WINDOW.PointerEvent ? 'pointermove' : 'touchmove mousemove'; +var EVENT_POINTER_UP = WINDOW.PointerEvent ? 'pointerup pointercancel' : 'touchend touchcancel mouseup'; +var EVENT_READY = 'ready'; +var EVENT_RESIZE = 'resize'; +var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; +var EVENT_ZOOM = 'zoom'; + +// RegExps +var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; +var REGEXP_DATA_URL = /^data:/; +var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/; +var REGEXP_TAG_NAME = /^(img|canvas)$/i; + +var DEFAULTS = { + // Define the view mode of the cropper + viewMode: 0, // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + dragMode: DRAG_MODE_CROP, // 'crop', 'move' or 'none' + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A selector for adding extra containers to preview + preview: '', + + // Re-render the cropper when resize the window + responsive: true, + + // Restore the cropped area after resize the window + restore: true, + + // Check if the current image is a cross-origin image + checkCrossOrigin: true, + + // Check the current image's Exif Orientation information + checkOrientation: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by dragging touch + zoomOnTouch: true, + + // Enable to zoom the image by wheeling mouse + zoomOnWheel: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + toggleDragModeOnDblclick: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + ready: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null +}; + +var TEMPLATE = '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
    ' + '
    '; + +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; +}; + + + + + + + + + + + +var classCallCheck = function (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 toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +/** + * Check if the given value is not a number. + */ +var isNaN = Number.isNaN || WINDOW.isNaN; + +/** + * Check if the given value is a number. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a number, else `false`. + */ +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +/** + * Check if the given value is undefined. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is undefined, else `false`. + */ +function isUndefined(value) { + return typeof value === 'undefined'; +} + +/** + * Check if the given value is an object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is an object, else `false`. + */ +function isObject(value) { + return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null; +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Check if the given value is a plain object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a plain object, else `false`. + */ + +function isPlainObject(value) { + if (!isObject(value)) { + return false; + } + + try { + var _constructor = value.constructor; + var prototype = _constructor.prototype; + + + return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (e) { + return false; + } +} + +/** + * Check if the given value is a function. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a function, else `false`. + */ +function isFunction(value) { + return typeof value === 'function'; +} + +/** + * Iterate the given data. + * @param {*} data - The data to iterate. + * @param {Function} callback - The process function for each element. + * @returns {*} The original data. + */ +function each(data, callback) { + if (data && isFunction(callback)) { + if (Array.isArray(data) || isNumber(data.length) /* array-like */) { + var length = data.length; + + var i = void 0; + + for (i = 0; i < length; i += 1) { + if (callback.call(data, data[i], i, data) === false) { + break; + } + } + } else if (isObject(data)) { + Object.keys(data).forEach(function (key) { + callback.call(data, data[key], key, data); + }); + } + } + + return data; +} + +/** + * Extend the given object. + * @param {*} obj - The object to be extended. + * @param {*} args - The rest objects which will be merged to the first object. + * @returns {Object} The extended object. + */ +function extend(obj) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (isObject(obj) && args.length > 0) { + if (Object.assign) { + return Object.assign.apply(Object, [obj].concat(args)); + } + + args.forEach(function (arg) { + if (isObject(arg)) { + Object.keys(arg).forEach(function (key) { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; +} + +/** + * Takes a function and returns a new one that will always have a particular context. + * @param {Function} fn - The target function. + * @param {Object} context - The new context for the function. + * @returns {boolean} The new function. + */ +function proxy(fn, context) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; + } + + return function () { + for (var _len3 = arguments.length, args2 = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args2[_key3] = arguments[_key3]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +var REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/i; + +/** + * Normalize decimal number. + * Check out {@link http://0.30000000000000004.com/ } + * @param {number} value - The value to normalize. + * @param {number} [times=100000000000] - The times for normalizing. + * @returns {number} Returns the normalized number. + */ +function normalizeDecimalNumber(value) { + var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000; + + return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value; +} + +var REGEXP_SUFFIX = /^(width|height|left|top|marginLeft|marginTop)$/; + +/** + * Apply styles to the given element. + * @param {Element} element - The target element. + * @param {Object} styles - The styles for applying. + */ +function setStyle(element, styles) { + var style = element.style; + + + each(styles, function (value, property) { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); +} + +/** + * Check if the given element has a special class. + * @param {Element} element - The element to check. + * @param {string} value - The class to search. + * @returns {boolean} Returns `true` if the special class was found. + */ +function hasClass(element, value) { + return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1; +} + +/** + * Add classes to the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be added. + */ +function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + var className = element.className.trim(); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = className + ' ' + value; + } +} + +/** + * Remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be removed. + */ +function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } +} + +/** + * Add or remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be toggled. + * @param {boolean} added - Add only. + */ +function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + toggleClass(elem, value, added); + }); + return; + } + + // IE10-11 doesn't support the second parameter of `classList.toggle` + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } +} + +var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; + +/** + * Hyphenate the given value. + * @param {string} value - The value to hyphenate. + * @returns {string} The hyphenated value. + */ +function hyphenate(value) { + return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); +} + +/** + * Get data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to get. + * @returns {string} The data value. + */ +function getData(element, name) { + if (isObject(element[name])) { + return element[name]; + } else if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute('data-' + hyphenate(name)); +} + +/** + * Set data to the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to set. + * @param {string} data - The data value. + */ +function setData(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute('data-' + hyphenate(name), data); + } +} + +/** + * Remove data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to remove. + */ +function removeData(element, name) { + if (isObject(element[name])) { + try { + delete element[name]; + } catch (e) { + element[name] = null; + } + } else if (element.dataset) { + // #128 Safari not allows to delete dataset property + try { + delete element.dataset[name]; + } catch (e) { + element.dataset[name] = null; + } + } else { + element.removeAttribute('data-' + hyphenate(name)); + } +} + +var REGEXP_SPACES = /\s+/; + +/** + * Remove event listener from the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function removeListener(element, type, listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + removeListener(element, t, listener, options); + }); + return; + } + + if (element.removeEventListener) { + element.removeEventListener(type, listener, options); + } else if (element.detachEvent) { + element.detachEvent('on' + type, listener); + } +} + +/** + * Add event listener to the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function addListener(element, type, _listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(_listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + addListener(element, t, _listener, options); + }); + return; + } + + if (options.once) { + var originalListener = _listener; + + _listener = function listener() { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + removeListener(element, type, _listener, options); + return originalListener.apply(element, args); + }; + } + + if (element.addEventListener) { + element.addEventListener(type, _listener, options); + } else if (element.attachEvent) { + element.attachEvent('on' + type, _listener); + } +} + +/** + * Dispatch event on the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Object} data - The additional event data. + * @returns {boolean} Indicate if the event is default prevented or not. + */ +function dispatchEvent(element, type, data) { + if (element.dispatchEvent) { + var event = void 0; + + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (isFunction(Event) && isFunction(CustomEvent)) { + if (isUndefined(data)) { + event = new Event(type, { + bubbles: true, + cancelable: true + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } + } else if (isUndefined(data)) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent('on' + type); + } + + return true; +} + +/** + * Get the offset base on the document. + * @param {Element} element - The target element. + * @returns {Object} The offset data. + */ +function getOffset(element) { + var doc = document.documentElement; + var box = element.getBoundingClientRect(); + + return { + left: box.left + ((window.scrollX || doc && doc.scrollLeft || 0) - (doc && doc.clientLeft || 0)), + top: box.top + ((window.scrollY || doc && doc.scrollTop || 0) - (doc && doc.clientTop || 0)) + }; +} + +/** + * Empty an element. + * @param {Element} element - The element to empty. + */ +function empty(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +var location = WINDOW.location; + +var REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i; + +/** + * Check if the given URL is a cross origin URL. + * @param {string} url - The target URL. + * @returns {boolean} Returns `true` if the given URL is a cross origin URL, else `false`. + */ +function isCrossOriginURL(url) { + var parts = url.match(REGEXP_ORIGINS); + + return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port); +} + +/** + * Add timestamp to the given URL. + * @param {string} url - The target URL. + * @returns {string} The result URL. + */ +function addTimestamp(url) { + var timestamp = 'timestamp=' + new Date().getTime(); + + return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp; +} + +/** + * Get transforms base on the given object. + * @param {Object} obj - The target object. + * @returns {string} A string contains transform values. + */ +function getTransforms(_ref) { + var rotate = _ref.rotate, + scaleX = _ref.scaleX, + scaleY = _ref.scaleY, + translateX = _ref.translateX, + translateY = _ref.translateY; + + var values = []; + + if (isNumber(translateX) && translateX !== 0) { + values.push('translateX(' + translateX + 'px)'); + } + + if (isNumber(translateY) && translateY !== 0) { + values.push('translateY(' + translateY + 'px)'); + } + + // Rotate should come first before scale to match orientation transform + if (isNumber(rotate) && rotate !== 0) { + values.push('rotate(' + rotate + 'deg)'); + } + + if (isNumber(scaleX) && scaleX !== 1) { + values.push('scaleX(' + scaleX + ')'); + } + + if (isNumber(scaleY) && scaleY !== 1) { + values.push('scaleY(' + scaleY + ')'); + } + + var transform = values.length ? values.join(' ') : 'none'; + + return { + WebkitTransform: transform, + msTransform: transform, + transform: transform + }; +} + +var navigator = WINDOW.navigator; + +var IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent); + +/** + * Get an image's natural sizes. + * @param {string} image - The target image. + * @param {Function} callback - The callback function. + */ +function getImageNaturalSizes(image, callback) { + // Modern browsers (except Safari) + if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) { + callback(image.naturalWidth, image.naturalHeight); + return; + } + + var newImage = document.createElement('img'); + var body = document.body || document.documentElement; + + newImage.onload = function () { + callback(newImage.width, newImage.height); + + if (!IS_SAFARI_OR_UIWEBVIEW) { + body.removeChild(newImage); + } + }; + + newImage.src = image.src; + + // iOS Safari will convert the image automatically + // with its orientation once append it into DOM (#279) + if (!IS_SAFARI_OR_UIWEBVIEW) { + newImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;'; + body.appendChild(newImage); + } +} + +/** + * Get the max ratio of a group of pointers. + * @param {string} pointers - The target pointers. + * @returns {number} The result ratio. + */ +function getMaxZoomRatio(pointers) { + var pointers2 = extend({}, pointers); + var ratios = []; + + each(pointers, function (pointer, pointerId) { + delete pointers2[pointerId]; + + each(pointers2, function (pointer2) { + var x1 = Math.abs(pointer.startX - pointer2.startX); + var y1 = Math.abs(pointer.startY - pointer2.startY); + var x2 = Math.abs(pointer.endX - pointer2.endX); + var y2 = Math.abs(pointer.endY - pointer2.endY); + var z1 = Math.sqrt(x1 * x1 + y1 * y1); + var z2 = Math.sqrt(x2 * x2 + y2 * y2); + var ratio = (z2 - z1) / z1; + + ratios.push(ratio); + }); + }); + + ratios.sort(function (a, b) { + return Math.abs(a) < Math.abs(b); + }); + + return ratios[0]; +} + +/** + * Get a pointer from an event object. + * @param {Object} event - The target event object. + * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not. + * @returns {Object} The result pointer contains start and/or end point coordinates. + */ +function getPointer(_ref2, endOnly) { + var pageX = _ref2.pageX, + pageY = _ref2.pageY; + + var end = { + endX: pageX, + endY: pageY + }; + + if (endOnly) { + return end; + } + + return extend({ + startX: pageX, + startY: pageY + }, end); +} + +/** + * Get the center point coordinate of a group of pointers. + * @param {Object} pointers - The target pointers. + * @returns {Object} The center point coordinate. + */ +function getPointersCenter(pointers) { + var pageX = 0; + var pageY = 0; + var count = 0; + + each(pointers, function (_ref3) { + var startX = _ref3.startX, + startY = _ref3.startY; + + pageX += startX; + pageY += startY; + count += 1; + }); + + pageX /= count; + pageY /= count; + + return { + pageX: pageX, + pageY: pageY + }; +} + +/** + * Check if the given value is a finite number. + */ +var isFinite = Number.isFinite || WINDOW.isFinite; + +/** + * Get the max sizes in a rectangle under the given aspect ratio. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getContainSizes(_ref4) { + var aspectRatio = _ref4.aspectRatio, + height = _ref4.height, + width = _ref4.width; + + var isValidNumber = function isValidNumber(value) { + return isFinite(value) && value > 0; + }; + + if (isValidNumber(width) && isValidNumber(height)) { + if (height * aspectRatio > width) { + height = width / aspectRatio; + } else { + width = height * aspectRatio; + } + } else if (isValidNumber(width)) { + height = width / aspectRatio; + } else if (isValidNumber(height)) { + width = height * aspectRatio; + } + + return { + width: width, + height: height + }; +} + +/** + * Get the new sizes of a rectangle after rotated. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getRotatedSizes(_ref5) { + var width = _ref5.width, + height = _ref5.height, + degree = _ref5.degree; + + degree = Math.abs(degree) % 180; + + if (degree === 90) { + return { + width: height, + height: width + }; + } + + var arc = degree % 90 * Math.PI / 180; + var sinArc = Math.sin(arc); + var cosArc = Math.cos(arc); + var newWidth = width * cosArc + height * sinArc; + var newHeight = width * sinArc + height * cosArc; + + return degree > 90 ? { + width: newHeight, + height: newWidth + } : { + width: newWidth, + height: newHeight + }; +} + +/** + * Get a canvas which drew the given image. + * @param {HTMLImageElement} image - The image for drawing. + * @param {Object} imageData - The image data. + * @param {Object} canvasData - The canvas data. + * @param {Object} options - The options. + * @returns {HTMLCanvasElement} The result canvas. + */ +function getSourceCanvas(image, _ref6, _ref7, _ref8) { + var imageNaturalWidth = _ref6.naturalWidth, + imageNaturalHeight = _ref6.naturalHeight, + _ref6$rotate = _ref6.rotate, + rotate = _ref6$rotate === undefined ? 0 : _ref6$rotate, + _ref6$scaleX = _ref6.scaleX, + scaleX = _ref6$scaleX === undefined ? 1 : _ref6$scaleX, + _ref6$scaleY = _ref6.scaleY, + scaleY = _ref6$scaleY === undefined ? 1 : _ref6$scaleY; + var aspectRatio = _ref7.aspectRatio, + naturalWidth = _ref7.naturalWidth, + naturalHeight = _ref7.naturalHeight; + var _ref8$fillColor = _ref8.fillColor, + fillColor = _ref8$fillColor === undefined ? 'transparent' : _ref8$fillColor, + _ref8$imageSmoothingE = _ref8.imageSmoothingEnabled, + imageSmoothingEnabled = _ref8$imageSmoothingE === undefined ? true : _ref8$imageSmoothingE, + _ref8$imageSmoothingQ = _ref8.imageSmoothingQuality, + imageSmoothingQuality = _ref8$imageSmoothingQ === undefined ? 'low' : _ref8$imageSmoothingQ, + _ref8$maxWidth = _ref8.maxWidth, + maxWidth = _ref8$maxWidth === undefined ? Infinity : _ref8$maxWidth, + _ref8$maxHeight = _ref8.maxHeight, + maxHeight = _ref8$maxHeight === undefined ? Infinity : _ref8$maxHeight, + _ref8$minWidth = _ref8.minWidth, + minWidth = _ref8$minWidth === undefined ? 0 : _ref8$minWidth, + _ref8$minHeight = _ref8.minHeight, + minHeight = _ref8$minHeight === undefined ? 0 : _ref8$minHeight; + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: maxWidth, + height: maxHeight + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minWidth, + height: minHeight + }); + var width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth)); + var height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight)); + var params = [-imageNaturalWidth / 2, -imageNaturalHeight / 2, imageNaturalWidth, imageNaturalHeight]; + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + context.fillStyle = fillColor; + context.fillRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + context.rotate(rotate * Math.PI / 180); + context.scale(scaleX, scaleY); + context.imageSmoothingEnabled = imageSmoothingEnabled; + context.imageSmoothingQuality = imageSmoothingQuality; + context.drawImage.apply(context, [image].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + context.restore(); + return canvas; +} + +var fromCharCode = String.fromCharCode; + +/** + * Get string from char code in data view. + * @param {DataView} dataView - The data view for read. + * @param {number} start - The start index. + * @param {number} length - The read length. + * @returns {string} The read result. + */ + +function getStringFromCharCode(dataView, start, length) { + var str = ''; + var i = void 0; + + length += start; + + for (i = start; i < length; i += 1) { + str += fromCharCode(dataView.getUint8(i)); + } + + return str; +} + +var REGEXP_DATA_URL_HEAD = /^data:.*,/; + +/** + * Transform Data URL to array buffer. + * @param {string} dataURL - The Data URL to transform. + * @returns {ArrayBuffer} The result array buffer. + */ +function dataURLToArrayBuffer(dataURL) { + var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); + var binary = atob(base64); + var arrayBuffer = new ArrayBuffer(binary.length); + var uint8 = new Uint8Array(arrayBuffer); + + each(uint8, function (value, i) { + uint8[i] = binary.charCodeAt(i); + }); + + return arrayBuffer; +} + +/** + * Transform array buffer to Data URL. + * @param {ArrayBuffer} arrayBuffer - The array buffer to transform. + * @param {string} mimeType - The mime type of the Data URL. + * @returns {string} The result Data URL. + */ +function arrayBufferToDataURL(arrayBuffer, mimeType) { + var uint8 = new Uint8Array(arrayBuffer); + var data = ''; + + // TypedArray.prototype.forEach is not supported in some browsers. + each(uint8, function (value) { + data += fromCharCode(value); + }); + + return 'data:' + mimeType + ';base64,' + btoa(data); +} + +/** + * Get orientation value from given array buffer. + * @param {ArrayBuffer} arrayBuffer - The array buffer to read. + * @returns {number} The read orientation value. + */ +function getOrientation(arrayBuffer) { + var dataView = new DataView(arrayBuffer); + var orientation = void 0; + var littleEndian = void 0; + var app1Start = void 0; + var ifdStart = void 0; + + // Only handle JPEG image (start by 0xFFD8) + if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { + var length = dataView.byteLength; + var offset = 2; + + while (offset < length) { + if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { + app1Start = offset; + break; + } + + offset += 1; + } + } + + if (app1Start) { + var exifIDCode = app1Start + 4; + var tiffOffset = app1Start + 10; + + if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { + var endianness = dataView.getUint16(tiffOffset); + + littleEndian = endianness === 0x4949; + + if (littleEndian || endianness === 0x4D4D /* bigEndian */) { + if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { + var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); + + if (firstIFDOffset >= 0x00000008) { + ifdStart = tiffOffset + firstIFDOffset; + } + } + } + } + } + + if (ifdStart) { + var _length = dataView.getUint16(ifdStart, littleEndian); + var _offset = void 0; + var i = void 0; + + for (i = 0; i < _length; i += 1) { + _offset = ifdStart + i * 12 + 2; + + if (dataView.getUint16(_offset, littleEndian) === 0x0112 /* Orientation */) { + // 8 is the offset of the current tag's value + _offset += 8; + + // Get the original orientation value + orientation = dataView.getUint16(_offset, littleEndian); + + // Override the orientation with its default value + dataView.setUint16(_offset, 1, littleEndian); + break; + } + } + } + + return orientation; +} + +/** + * Parse Exif Orientation value. + * @param {number} orientation - The orientation to parse. + * @returns {Object} The parsed result. + */ +function parseOrientation(orientation) { + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + switch (orientation) { + // Flip horizontal + case 2: + scaleX = -1; + break; + + // Rotate left 180° + case 3: + rotate = -180; + break; + + // Flip vertical + case 4: + scaleY = -1; + break; + + // Flip vertical and rotate right 90° + case 5: + rotate = 90; + scaleY = -1; + break; + + // Rotate right 90° + case 6: + rotate = 90; + break; + + // Flip horizontal and rotate right 90° + case 7: + rotate = 90; + scaleX = -1; + break; + + // Rotate left 90° + case 8: + rotate = -90; + break; + + default: + } + + return { + rotate: rotate, + scaleX: scaleX, + scaleY: scaleY + }; +} + +var render = { + render: function render() { + this.initContainer(); + this.initCanvas(); + this.initCropBox(); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + }, + initContainer: function initContainer() { + var element = this.element, + options = this.options, + container = this.container, + cropper = this.cropper; + + + addClass(cropper, CLASS_HIDDEN); + removeClass(element, CLASS_HIDDEN); + + var containerData = { + width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200), + height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100) + }; + + this.containerData = containerData; + + setStyle(cropper, { + width: containerData.width, + height: containerData.height + }); + + addClass(element, CLASS_HIDDEN); + removeClass(cropper, CLASS_HIDDEN); + }, + + + // Canvas (image wrapper) + initCanvas: function initCanvas() { + var containerData = this.containerData, + imageData = this.imageData; + var viewMode = this.options.viewMode; + + var rotated = Math.abs(imageData.rotate) % 180 === 90; + var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth; + var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight; + var aspectRatio = naturalWidth / naturalHeight; + var canvasWidth = containerData.width; + var canvasHeight = containerData.height; + + if (containerData.height * aspectRatio > containerData.width) { + if (viewMode === 3) { + canvasWidth = containerData.height * aspectRatio; + } else { + canvasHeight = containerData.width / aspectRatio; + } + } else if (viewMode === 3) { + canvasHeight = containerData.width / aspectRatio; + } else { + canvasWidth = containerData.height * aspectRatio; + } + + var canvasData = { + aspectRatio: aspectRatio, + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + width: canvasWidth, + height: canvasHeight + }; + + canvasData.left = (containerData.width - canvasWidth) / 2; + canvasData.top = (containerData.height - canvasHeight) / 2; + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + this.canvasData = canvasData; + this.limited = viewMode === 1 || viewMode === 2; + this.limitCanvas(true, true); + this.initialImageData = extend({}, imageData); + this.initialCanvasData = extend({}, canvasData); + }, + limitCanvas: function limitCanvas(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var viewMode = options.viewMode; + var aspectRatio = canvasData.aspectRatio; + + var cropped = this.cropped && cropBoxData; + + if (sizeLimited) { + var minCanvasWidth = Number(options.minCanvasWidth) || 0; + var minCanvasHeight = Number(options.minCanvasHeight) || 0; + + if (viewMode > 1) { + minCanvasWidth = Math.max(minCanvasWidth, containerData.width); + minCanvasHeight = Math.max(minCanvasHeight, containerData.height); + + if (viewMode === 3) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } else if (viewMode > 0) { + if (minCanvasWidth) { + minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0); + } else if (minCanvasHeight) { + minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0); + } else if (cropped) { + minCanvasWidth = cropBoxData.width; + minCanvasHeight = cropBoxData.height; + + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minCanvasWidth, + height: minCanvasHeight + }); + + minCanvasWidth = _getContainSizes.width; + minCanvasHeight = _getContainSizes.height; + + + canvasData.minWidth = minCanvasWidth; + canvasData.minHeight = minCanvasHeight; + canvasData.maxWidth = Infinity; + canvasData.maxHeight = Infinity; + } + + if (positionLimited) { + if (viewMode) { + var newCanvasLeft = containerData.width - canvasData.width; + var newCanvasTop = containerData.height - canvasData.height; + + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + canvasData.maxTop = Math.max(0, newCanvasTop); + + if (cropped && this.limited) { + canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width)); + canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height)); + canvasData.maxLeft = cropBoxData.left; + canvasData.maxTop = cropBoxData.top; + + if (viewMode === 2) { + if (canvasData.width >= containerData.width) { + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + } + + if (canvasData.height >= containerData.height) { + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxTop = Math.max(0, newCanvasTop); + } + } + } + } else { + canvasData.minLeft = -canvasData.width; + canvasData.minTop = -canvasData.height; + canvasData.maxLeft = containerData.width; + canvasData.maxTop = containerData.height; + } + } + }, + renderCanvas: function renderCanvas(changed, transformed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + + if (transformed) { + var _getRotatedSizes = getRotatedSizes({ + width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1), + height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1), + degree: imageData.rotate || 0 + }), + naturalWidth = _getRotatedSizes.width, + naturalHeight = _getRotatedSizes.height; + + var width = canvasData.width * (naturalWidth / canvasData.naturalWidth); + var height = canvasData.height * (naturalHeight / canvasData.naturalHeight); + + canvasData.left -= (width - canvasData.width) / 2; + canvasData.top -= (height - canvasData.height) / 2; + canvasData.width = width; + canvasData.height = height; + canvasData.aspectRatio = naturalWidth / naturalHeight; + canvasData.naturalWidth = naturalWidth; + canvasData.naturalHeight = naturalHeight; + this.limitCanvas(true, false); + } + + if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) { + canvasData.left = canvasData.oldLeft; + } + + if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) { + canvasData.top = canvasData.oldTop; + } + + canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth); + canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight); + + this.limitCanvas(false, true); + + canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft); + canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop); + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + setStyle(this.canvas, extend({ + width: canvasData.width, + height: canvasData.height + }, getTransforms({ + translateX: canvasData.left, + translateY: canvasData.top + }))); + + this.renderImage(changed); + + if (this.cropped && this.limited) { + this.limitCropBox(true, true); + } + }, + renderImage: function renderImage(changed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + var width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth); + var height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight); + + extend(imageData, { + width: width, + height: height, + left: (canvasData.width - width) / 2, + top: (canvasData.height - height) / 2 + }); + setStyle(this.image, extend({ + width: imageData.width, + height: imageData.height + }, getTransforms(extend({ + translateX: imageData.left, + translateY: imageData.top + }, imageData)))); + + if (changed) { + this.output(); + } + }, + initCropBox: function initCropBox() { + var options = this.options, + canvasData = this.canvasData; + var aspectRatio = options.aspectRatio; + + var autoCropArea = Number(options.autoCropArea) || 0.8; + var cropBoxData = { + width: canvasData.width, + height: canvasData.height + }; + + if (aspectRatio) { + if (canvasData.height * aspectRatio > canvasData.width) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.cropBoxData = cropBoxData; + this.limitCropBox(true, true); + + // Initialize auto crop area + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + // The width/height of auto crop area must large than "minWidth/Height" + cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea); + cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea); + cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2; + cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2; + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + this.initialCropBoxData = extend({}, cropBoxData); + }, + limitCropBox: function limitCropBox(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData, + limited = this.limited; + var aspectRatio = options.aspectRatio; + + + if (sizeLimited) { + var minCropBoxWidth = Number(options.minCropBoxWidth) || 0; + var minCropBoxHeight = Number(options.minCropBoxHeight) || 0; + var maxCropBoxWidth = Math.min(containerData.width, limited ? canvasData.width : containerData.width); + var maxCropBoxHeight = Math.min(containerData.height, limited ? canvasData.height : containerData.height); + + // The min/maxCropBoxWidth/Height must be less than container's width/height + minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width); + minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height); + + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } + } + + // The minWidth/Height must be less than maxWidth/Height + cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth); + cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight); + cropBoxData.maxWidth = maxCropBoxWidth; + cropBoxData.maxHeight = maxCropBoxHeight; + } + + if (positionLimited) { + if (limited) { + cropBoxData.minLeft = Math.max(0, canvasData.left); + cropBoxData.minTop = Math.max(0, canvasData.top); + cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width; + cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height; + } else { + cropBoxData.minLeft = 0; + cropBoxData.minTop = 0; + cropBoxData.maxLeft = containerData.width - cropBoxData.width; + cropBoxData.maxTop = containerData.height - cropBoxData.height; + } + } + }, + renderCropBox: function renderCropBox() { + var options = this.options, + containerData = this.containerData, + cropBoxData = this.cropBoxData; + + + if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) { + cropBoxData.left = cropBoxData.oldLeft; + } + + if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) { + cropBoxData.top = cropBoxData.oldTop; + } + + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + this.limitCropBox(false, true); + + cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft); + cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop); + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + if (options.movable && options.cropBoxMovable) { + // Turn to move the canvas when the crop box is equal to the container + setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width && cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL); + } + + setStyle(this.cropBox, extend({ + width: cropBoxData.width, + height: cropBoxData.height + }, getTransforms({ + translateX: cropBoxData.left, + translateY: cropBoxData.top + }))); + + if (this.cropped && this.limited) { + this.limitCanvas(true, true); + } + + if (!this.disabled) { + this.output(); + } + }, + output: function output() { + this.preview(); + + if (this.complete) { + dispatchEvent(this.element, EVENT_CROP, this.getData()); + } + } +}; + +var preview = { + initPreview: function initPreview() { + var crossOrigin = this.crossOrigin; + var preview = this.options.preview; + + var url = crossOrigin ? this.crossOriginUrl : this.url; + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = url; + this.viewBox.appendChild(image); + this.image2 = image; + + if (!preview) { + return; + } + + var previews = preview.querySelector ? [preview] : document.querySelectorAll(preview); + + this.previews = previews; + + each(previews, function (element) { + var img = document.createElement('img'); + + // Save the original size for recover + setData(element, DATA_PREVIEW, { + width: element.offsetWidth, + height: element.offsetHeight, + html: element.innerHTML + }); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * Add `height:auto` to override `height` attribute on IE8 + * (Occur only when margin-top <= -height) + */ + img.style.cssText = 'display:block;' + 'width:100%;' + 'height:auto;' + 'min-width:0!important;' + 'min-height:0!important;' + 'max-width:none!important;' + 'max-height:none!important;' + 'image-orientation:0deg!important;"'; + + empty(element); + element.appendChild(img); + }); + }, + resetPreview: function resetPreview() { + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + + setStyle(element, { + width: data.width, + height: data.height + }); + + element.innerHTML = data.html; + removeData(element, DATA_PREVIEW); + }); + }, + preview: function preview() { + var imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var cropBoxWidth = cropBoxData.width, + cropBoxHeight = cropBoxData.height; + var width = imageData.width, + height = imageData.height; + + var left = cropBoxData.left - canvasData.left - imageData.left; + var top = cropBoxData.top - canvasData.top - imageData.top; + + if (!this.cropped || this.disabled) { + return; + } + + setStyle(this.image2, extend({ + width: width, + height: height + }, getTransforms(extend({ + translateX: -left, + translateY: -top + }, imageData)))); + + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + var originalWidth = data.width; + var originalHeight = data.height; + var newWidth = originalWidth; + var newHeight = originalHeight; + var ratio = 1; + + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; + } + + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } + + setStyle(element, { + width: newWidth, + height: newHeight + }); + + setStyle(element.getElementsByTagName('img')[0], extend({ + width: width * ratio, + height: height * ratio + }, getTransforms(extend({ + translateX: -left * ratio, + translateY: -top * ratio + }, imageData)))); + }); + } +}; + +var events = { + bind: function bind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + addListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + addListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + addListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + addListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom); + } + + addListener(cropper, EVENT_POINTER_DOWN, this.onCropStart = proxy(this.cropStart, this)); + + if (options.zoomable && options.zoomOnWheel) { + addListener(cropper, EVENT_WHEEL, this.onWheel = proxy(this.wheel, this)); + } + + if (options.toggleDragModeOnDblclick) { + addListener(cropper, EVENT_DBLCLICK, this.onDblclick = proxy(this.dblclick, this)); + } + + addListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove = proxy(this.cropMove, this)); + addListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd = proxy(this.cropEnd, this)); + + if (options.responsive) { + addListener(window, EVENT_RESIZE, this.onResize = proxy(this.resize, this)); + } + }, + unbind: function unbind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + removeListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + removeListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + removeListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + removeListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + removeListener(element, EVENT_ZOOM, options.zoom); + } + + removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart); + + if (options.zoomable && options.zoomOnWheel) { + removeListener(cropper, EVENT_WHEEL, this.onWheel); + } + + if (options.toggleDragModeOnDblclick) { + removeListener(cropper, EVENT_DBLCLICK, this.onDblclick); + } + + removeListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove); + removeListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd); + + if (options.responsive) { + removeListener(window, EVENT_RESIZE, this.onResize); + } + } +}; + +var handlers = { + resize: function resize() { + var options = this.options, + container = this.container, + containerData = this.containerData; + + var minContainerWidth = Number(options.minContainerWidth) || 200; + var minContainerHeight = Number(options.minContainerHeight) || 100; + + if (this.disabled || containerData.width <= minContainerWidth || containerData.height <= minContainerHeight) { + return; + } + + var ratio = container.offsetWidth / containerData.width; + + // Resize when width changed or height changed + if (ratio !== 1 || container.offsetHeight !== containerData.height) { + var canvasData = void 0; + var cropBoxData = void 0; + + if (options.restore) { + canvasData = this.getCanvasData(); + cropBoxData = this.getCropBoxData(); + } + + this.render(); + + if (options.restore) { + this.setCanvasData(each(canvasData, function (n, i) { + canvasData[i] = n * ratio; + })); + this.setCropBoxData(each(cropBoxData, function (n, i) { + cropBoxData[i] = n * ratio; + })); + } + } + }, + dblclick: function dblclick() { + if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) { + return; + } + + this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP); + }, + wheel: function wheel(e) { + var _this = this; + + var ratio = Number(this.options.wheelZoomRatio) || 0.1; + var delta = 1; + + if (this.disabled) { + return; + } + + e.preventDefault(); + + // Limit wheel speed to prevent zoom too fast (#21) + if (this.wheeling) { + return; + } + + this.wheeling = true; + + setTimeout(function () { + _this.wheeling = false; + }, 50); + + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + this.zoom(-delta * ratio, e); + }, + cropStart: function cropStart(e) { + if (this.disabled) { + return; + } + + var options = this.options, + pointers = this.pointers; + + var action = void 0; + + if (e.changedTouches) { + // Handle touch event + each(e.changedTouches, function (touch) { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + // Handle mouse event and pointer event + pointers[e.pointerId || 0] = getPointer(e); + } + + if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { + action = ACTION_ZOOM; + } else { + action = getData(e.target, DATA_ACTION); + } + + if (!REGEXP_ACTIONS.test(action)) { + return; + } + + if (dispatchEvent(this.element, EVENT_CROP_START, { + originalEvent: e, + action: action + }) === false) { + return; + } + + e.preventDefault(); + + this.action = action; + this.cropping = false; + + if (action === ACTION_CROP) { + this.cropping = true; + addClass(this.dragBox, CLASS_MODAL); + } + }, + cropMove: function cropMove(e) { + var action = this.action; + + + if (this.disabled || !action) { + return; + } + + var pointers = this.pointers; + + + e.preventDefault(); + + if (dispatchEvent(this.element, EVENT_CROP_MOVE, { + originalEvent: e, + action: action + }) === false) { + return; + } + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + extend(pointers[touch.identifier], getPointer(touch, true)); + }); + } else { + extend(pointers[e.pointerId || 0], getPointer(e, true)); + } + + this.change(e); + }, + cropEnd: function cropEnd(e) { + if (this.disabled) { + return; + } + + var action = this.action, + pointers = this.pointers; + + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + delete pointers[touch.identifier]; + }); + } else { + delete pointers[e.pointerId || 0]; + } + + if (!action) { + return; + } + + e.preventDefault(); + + if (!Object.keys(pointers).length) { + this.action = ''; + } + + if (this.cropping) { + this.cropping = false; + toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal); + } + + dispatchEvent(this.element, EVENT_CROP_END, { + originalEvent: e, + action: action + }); + } +}; + +var change = { + change: function change(e) { + var options = this.options, + canvasData = this.canvasData, + containerData = this.containerData, + cropBoxData = this.cropBoxData, + pointers = this.pointers; + var action = this.action; + var aspectRatio = options.aspectRatio; + var left = cropBoxData.left, + top = cropBoxData.top, + width = cropBoxData.width, + height = cropBoxData.height; + + var right = left + width; + var bottom = top + height; + var minLeft = 0; + var minTop = 0; + var maxWidth = containerData.width; + var maxHeight = containerData.height; + var renderable = true; + var offset = void 0; + + // Locking aspect ratio in "free mode" by holding shift key + if (!aspectRatio && e.shiftKey) { + aspectRatio = width && height ? width / height : 1; + } + + if (this.limited) { + minLeft = cropBoxData.minLeft; + minTop = cropBoxData.minTop; + + maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width); + maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height); + } + + var pointer = pointers[Object.keys(pointers)[0]]; + var range = { + x: pointer.endX - pointer.startX, + y: pointer.endY - pointer.startY + }; + var check = function check(side) { + switch (side) { + case ACTION_EAST: + if (right + range.x > maxWidth) { + range.x = maxWidth - right; + } + + break; + + case ACTION_WEST: + if (left + range.x < minLeft) { + range.x = minLeft - left; + } + + break; + + case ACTION_NORTH: + if (top + range.y < minTop) { + range.y = minTop - top; + } + + break; + + case ACTION_SOUTH: + if (bottom + range.y > maxHeight) { + range.y = maxHeight - bottom; + } + + break; + + default: + } + }; + + switch (action) { + // Move crop box + case ACTION_ALL: + left += range.x; + top += range.y; + break; + + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_WEST; + width = 0; + } + + break; + + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_SOUTH; + height = 0; + } + + break; + + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_EAST; + width = 0; + } + + break; + + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_SOUTH); + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_NORTH; + height = 0; + } + + break; + + case ACTION_NORTH_EAST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + } + + break; + + case ACTION_NORTH_WEST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.y * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_WEST: + if (aspectRatio) { + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_EAST: + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + } + + break; + + // Move canvas + case ACTION_MOVE: + this.move(range.x, range.y); + renderable = false; + break; + + // Zoom canvas + case ACTION_ZOOM: + this.zoom(getMaxZoomRatio(pointers), e); + renderable = false; + break; + + // Create crop box + case ACTION_CROP: + if (!range.x || !range.y) { + renderable = false; + break; + } + + offset = getOffset(this.cropper); + left = pointer.startX - offset.left; + top = pointer.startY - offset.top; + width = cropBoxData.minWidth; + height = cropBoxData.minHeight; + + if (range.x > 0) { + action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; + } else if (range.x < 0) { + left -= width; + action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; + } + + if (range.y < 0) { + top -= height; + } + + // Show the crop box if is hidden + if (!this.cropped) { + removeClass(this.cropBox, CLASS_HIDDEN); + this.cropped = true; + + if (this.limited) { + this.limitCropBox(true, true); + } + } + + break; + + default: + } + + if (renderable) { + cropBoxData.width = width; + cropBoxData.height = height; + cropBoxData.left = left; + cropBoxData.top = top; + this.action = action; + this.renderCropBox(); + } + + // Override + each(pointers, function (p) { + p.startX = p.endX; + p.startY = p.endY; + }); + } +}; + +var methods = { + // Show the crop box manually + crop: function crop() { + if (this.ready && !this.disabled) { + if (!this.cropped) { + this.cropped = true; + this.limitCropBox(true, true); + + if (this.options.modal) { + addClass(this.dragBox, CLASS_MODAL); + } + + removeClass(this.cropBox, CLASS_HIDDEN); + } + + this.setCropBoxData(this.initialCropBoxData); + } + + return this; + }, + + + // Reset the image and crop box to their initial states + reset: function reset() { + if (this.ready && !this.disabled) { + this.imageData = extend({}, this.initialImageData); + this.canvasData = extend({}, this.initialCanvasData); + this.cropBoxData = extend({}, this.initialCropBoxData); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + } + + return this; + }, + + + // Clear the crop box + clear: function clear() { + if (this.cropped && !this.disabled) { + extend(this.cropBoxData, { + left: 0, + top: 0, + width: 0, + height: 0 + }); + + this.cropped = false; + this.renderCropBox(); + this.limitCanvas(true, true); + + // Render canvas after crop box rendered + this.renderCanvas(); + removeClass(this.dragBox, CLASS_MODAL); + addClass(this.cropBox, CLASS_HIDDEN); + } + + return this; + }, + + + /** + * Replace the image's src and rebuild the cropper + * @param {string} url - The new URL. + * @param {boolean} [onlyColorChanged] - Indicate if the new image only changed color. + * @returns {Object} this + */ + replace: function replace(url) { + var onlyColorChanged = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!this.disabled && url) { + if (this.isImg) { + this.element.src = url; + } + + if (onlyColorChanged) { + this.url = url; + this.image.src = url; + + if (this.ready) { + this.image2.src = url; + + each(this.previews, function (element) { + element.getElementsByTagName('img')[0].src = url; + }); + } + } else { + if (this.isImg) { + this.replaced = true; + } + + // Clear previous data + this.options.data = null; + this.load(url); + } + } + + return this; + }, + + + // Enable (unfreeze) the cropper + enable: function enable() { + if (this.ready) { + this.disabled = false; + removeClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Disable (freeze) the cropper + disable: function disable() { + if (this.ready) { + this.disabled = true; + addClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Destroy the cropper and remove the instance from the image + destroy: function destroy() { + var element = this.element, + image = this.image; + + + if (this.loaded) { + if (this.isImg && this.replaced) { + element.src = this.originalUrl; + } + + this.unbuild(); + removeClass(element, CLASS_HIDDEN); + } else if (this.isImg) { + removeListener(element, EVENT_LOAD, this.onStart); + } else if (image) { + image.parentNode.removeChild(image); + } + + removeData(element, NAMESPACE); + + return this; + }, + + + /** + * Move the canvas with relative offsets + * @param {number} offsetX - The relative offset distance on the x-axis. + * @param {number} offsetY - The relative offset distance on the y-axis. + * @returns {Object} this + */ + move: function move(offsetX, offsetY) { + var _canvasData = this.canvasData, + left = _canvasData.left, + top = _canvasData.top; + + + return this.moveTo(isUndefined(offsetX) ? offsetX : left + Number(offsetX), isUndefined(offsetY) ? offsetY : top + Number(offsetY)); + }, + + + /** + * Move the canvas to an absolute point + * @param {number} x - The x-axis coordinate. + * @param {number} [y=x] - The y-axis coordinate. + * @returns {Object} this + */ + moveTo: function moveTo(x) { + var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x; + var canvasData = this.canvasData; + + var changed = false; + + x = Number(x); + y = Number(y); + + if (this.ready && !this.disabled && this.options.movable) { + if (isNumber(x)) { + canvasData.left = x; + changed = true; + } + + if (isNumber(y)) { + canvasData.top = y; + changed = true; + } + + if (changed) { + this.renderCanvas(true); + } + } + + return this; + }, + + + /** + * Zoom the canvas with a relative ratio + * @param {number} ratio - The target ratio. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoom: function zoom(ratio, _originalEvent) { + var canvasData = this.canvasData; + + + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + return this.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, null, _originalEvent); + }, + + + /** + * Zoom the canvas to an absolute ratio + * @param {number} ratio - The target ratio. + * @param {Object} pivot - The zoom pivot point coordinate. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoomTo: function zoomTo(ratio, pivot, _originalEvent) { + var options = this.options, + canvasData = this.canvasData; + var width = canvasData.width, + height = canvasData.height, + naturalWidth = canvasData.naturalWidth, + naturalHeight = canvasData.naturalHeight; + + + ratio = Number(ratio); + + if (ratio >= 0 && this.ready && !this.disabled && options.zoomable) { + var newWidth = naturalWidth * ratio; + var newHeight = naturalHeight * ratio; + + if (dispatchEvent(this.element, EVENT_ZOOM, { + originalEvent: _originalEvent, + oldRatio: width / naturalWidth, + ratio: newWidth / naturalWidth + }) === false) { + return this; + } + + if (_originalEvent) { + var pointers = this.pointers; + + var offset = getOffset(this.cropper); + var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY + }; + + // Zoom from the triggering point of the event + canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height); + } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) { + canvasData.left -= (newWidth - width) * ((pivot.x - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((pivot.y - canvasData.top) / height); + } else { + // Zoom from the center of the canvas + canvasData.left -= (newWidth - width) / 2; + canvasData.top -= (newHeight - height) / 2; + } + + canvasData.width = newWidth; + canvasData.height = newHeight; + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Rotate the canvas with a relative degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotate: function rotate(degree) { + return this.rotateTo((this.imageData.rotate || 0) + Number(degree)); + }, + + + /** + * Rotate the canvas to an absolute degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotateTo: function rotateTo(degree) { + degree = Number(degree); + + if (isNumber(degree) && this.ready && !this.disabled && this.options.rotatable) { + this.imageData.rotate = degree % 360; + this.renderCanvas(true, true); + } + + return this; + }, + + + /** + * Scale the image on the x-axis. + * @param {number} scaleX - The scale ratio on the x-axis. + * @returns {Object} this + */ + scaleX: function scaleX(_scaleX) { + var scaleY = this.imageData.scaleY; + + + return this.scale(_scaleX, isNumber(scaleY) ? scaleY : 1); + }, + + + /** + * Scale the image on the y-axis. + * @param {number} scaleY - The scale ratio on the y-axis. + * @returns {Object} this + */ + scaleY: function scaleY(_scaleY) { + var scaleX = this.imageData.scaleX; + + + return this.scale(isNumber(scaleX) ? scaleX : 1, _scaleY); + }, + + + /** + * Scale the image + * @param {number} scaleX - The scale ratio on the x-axis. + * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. + * @returns {Object} this + */ + scale: function scale(scaleX) { + var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX; + var imageData = this.imageData; + + var transformed = false; + + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (this.ready && !this.disabled && this.options.scalable) { + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + transformed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + transformed = true; + } + + if (transformed) { + this.renderCanvas(true, true); + } + } + + return this; + }, + + + /** + * Get the cropped area position and size data (base on the original image) + * @param {boolean} [rounded=false] - Indicate if round the data values or not. + * @returns {Object} The result cropped data. + */ + getData: function getData$$1() { + var rounded = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + x: cropBoxData.left - canvasData.left, + y: cropBoxData.top - canvasData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + + var ratio = imageData.width / imageData.naturalWidth; + + each(data, function (n, i) { + n /= ratio; + data[i] = rounded ? Math.round(n) : n; + }); + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0 + }; + } + + if (options.rotatable) { + data.rotate = imageData.rotate || 0; + } + + if (options.scalable) { + data.scaleX = imageData.scaleX || 1; + data.scaleY = imageData.scaleY || 1; + } + + return data; + }, + + + /** + * Set the cropped area position and size with new data + * @param {Object} data - The new data. + * @returns {Object} this + */ + setData: function setData$$1(data) { + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData; + + var cropBoxData = {}; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + var transformed = false; + + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== imageData.rotate) { + imageData.rotate = data.rotate; + transformed = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) { + imageData.scaleX = data.scaleX; + transformed = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) { + imageData.scaleY = data.scaleY; + transformed = true; + } + } + + if (transformed) { + this.renderCanvas(true, true); + } + + var ratio = imageData.width / imageData.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = data.x * ratio + canvasData.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = data.y * ratio + canvasData.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + this.setCropBoxData(cropBoxData); + } + + return this; + }, + + + /** + * Get the container size data. + * @returns {Object} The result container data. + */ + getContainerData: function getContainerData() { + return this.ready ? extend({}, this.containerData) : {}; + }, + + + /** + * Get the image position and size data. + * @returns {Object} The result image data. + */ + getImageData: function getImageData() { + return this.loaded ? extend({}, this.imageData) : {}; + }, + + + /** + * Get the canvas position and size data. + * @returns {Object} The result canvas data. + */ + getCanvasData: function getCanvasData() { + var canvasData = this.canvasData; + + var data = {}; + + if (this.ready) { + each(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) { + data[n] = canvasData[n]; + }); + } + + return data; + }, + + + /** + * Set the canvas position and size with new data. + * @param {Object} data - The new canvas data. + * @returns {Object} this + */ + setCanvasData: function setCanvasData(data) { + var canvasData = this.canvasData; + var aspectRatio = canvasData.aspectRatio; + + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + canvasData.left = data.left; + } + + if (isNumber(data.top)) { + canvasData.top = data.top; + } + + if (isNumber(data.width)) { + canvasData.width = data.width; + canvasData.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvasData.height = data.height; + canvasData.width = data.height * aspectRatio; + } + + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Get the crop box position and size data. + * @returns {Object} The result crop box data. + */ + getCropBoxData: function getCropBoxData() { + var cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + left: cropBoxData.left, + top: cropBoxData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + } + + return data || {}; + }, + + + /** + * Set the crop box position and size with new data. + * @param {Object} data - The new crop box data. + * @returns {Object} this + */ + setCropBoxData: function setCropBoxData(data) { + var cropBoxData = this.cropBoxData; + var aspectRatio = this.options.aspectRatio; + + var widthChanged = void 0; + var heightChanged = void 0; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + cropBoxData.left = data.left; + } + + if (isNumber(data.top)) { + cropBoxData.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBoxData.width) { + widthChanged = true; + cropBoxData.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBoxData.height) { + heightChanged = true; + cropBoxData.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else if (heightChanged) { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.renderCropBox(); + } + + return this; + }, + + + /** + * Get a canvas drawn the cropped image. + * @param {Object} [options={}] - The config options. + * @returns {HTMLCanvasElement} - The result canvas. + */ + getCroppedCanvas: function getCroppedCanvas() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (!this.ready || !window.HTMLCanvasElement) { + return null; + } + + var canvasData = this.canvasData; + + var source = getSourceCanvas(this.image, this.imageData, canvasData, options); + + // Returns the source canvas if it is not cropped. + if (!this.cropped) { + return source; + } + + var _getData = this.getData(), + x = _getData.x, + y = _getData.y, + initialWidth = _getData.width, + initialHeight = _getData.height; + + var aspectRatio = initialWidth / initialHeight; + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.maxWidth || Infinity, + height: options.maxHeight || Infinity + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.minWidth || 0, + height: options.minHeight || 0 + }); + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.width || initialWidth, + height: options.height || initialHeight + }), + width = _getContainSizes.width, + height = _getContainSizes.height; + + width = Math.min(maxSizes.width, Math.max(minSizes.width, width)); + height = Math.min(maxSizes.height, Math.max(minSizes.height, height)); + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + + context.fillStyle = options.fillColor || 'transparent'; + context.fillRect(0, 0, width, height); + + var _options$imageSmoothi = options.imageSmoothingEnabled, + imageSmoothingEnabled = _options$imageSmoothi === undefined ? true : _options$imageSmoothi, + imageSmoothingQuality = options.imageSmoothingQuality; + + + context.imageSmoothingEnabled = imageSmoothingEnabled; + + if (imageSmoothingQuality) { + context.imageSmoothingQuality = imageSmoothingQuality; + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + var sourceWidth = source.width; + var sourceHeight = source.height; + + // Source canvas parameters + var srcX = x; + var srcY = y; + var srcWidth = void 0; + var srcHeight = void 0; + + // Destination canvas parameters + var dstX = void 0; + var dstY = void 0; + var dstWidth = void 0; + var dstHeight = void 0; + + if (srcX <= -initialWidth || srcX > sourceWidth) { + srcX = 0; + srcWidth = 0; + dstX = 0; + dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = Math.min(sourceWidth, initialWidth + srcX); + dstWidth = srcWidth; + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = Math.min(initialWidth, sourceWidth - srcX); + dstWidth = srcWidth; + } + + if (srcWidth <= 0 || srcY <= -initialHeight || srcY > sourceHeight) { + srcY = 0; + srcHeight = 0; + dstY = 0; + dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = Math.min(sourceHeight, initialHeight + srcY); + dstHeight = srcHeight; + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = Math.min(initialHeight, sourceHeight - srcY); + dstHeight = srcHeight; + } + + // All the numerical parameters should be integer for `drawImage` + // https://github.com/fengyuanchen/cropper/issues/476 + var params = [srcX, srcY, srcWidth, srcHeight]; + + // Avoid "IndexSizeError" + if (dstWidth > 0 && dstHeight > 0) { + var scale = width / initialWidth; + + params.push(dstX * scale, dstY * scale, dstWidth * scale, dstHeight * scale); + } + + context.drawImage.apply(context, [source].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + + return canvas; + }, + + + /** + * Change the aspect ratio of the crop box. + * @param {number} aspectRatio - The new aspect ratio. + * @returns {Object} this + */ + setAspectRatio: function setAspectRatio(aspectRatio) { + var options = this.options; + + + if (!this.disabled && !isUndefined(aspectRatio)) { + // 0 -> NaN + options.aspectRatio = Math.max(0, aspectRatio) || NaN; + + if (this.ready) { + this.initCropBox(); + + if (this.cropped) { + this.renderCropBox(); + } + } + } + + return this; + }, + + + /** + * Change the drag mode. + * @param {string} mode - The new drag mode. + * @returns {Object} this + */ + setDragMode: function setDragMode(mode) { + var options = this.options, + dragBox = this.dragBox, + face = this.face; + + + if (this.loaded && !this.disabled) { + var croppable = mode === DRAG_MODE_CROP; + var movable = options.movable && mode === DRAG_MODE_MOVE; + + mode = croppable || movable ? mode : DRAG_MODE_NONE; + + setData(dragBox, DATA_ACTION, mode); + toggleClass(dragBox, CLASS_CROP, croppable); + toggleClass(dragBox, CLASS_MOVE, movable); + + if (!options.cropBoxMovable) { + // Sync drag mode to crop box when it is not movable + setData(face, DATA_ACTION, mode); + toggleClass(face, CLASS_CROP, croppable); + toggleClass(face, CLASS_MOVE, movable); + } + } + + return this; + } +}; + +var AnotherCropper = WINDOW.Cropper; + +var Cropper = function () { + /** + * Create a new Cropper. + * @param {Element} element - The target element for cropping. + * @param {Object} [options={}] - The configuration options. + */ + function Cropper(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, Cropper); + + if (!element || !REGEXP_TAG_NAME.test(element.tagName)) { + throw new Error('The first argument is required and must be an or element.'); + } + + this.element = element; + this.options = extend({}, DEFAULTS, isPlainObject(options) && options); + this.complete = false; + this.cropped = false; + this.disabled = false; + this.isImg = false; + this.limited = false; + this.loaded = false; + this.ready = false; + this.replaced = false; + this.wheeling = false; + this.originalUrl = ''; + this.canvasData = null; + this.cropBoxData = null; + this.previews = null; + this.pointers = {}; + this.init(); + } + + createClass(Cropper, [{ + key: 'init', + value: function init() { + var element = this.element; + + var tagName = element.tagName.toLowerCase(); + var url = void 0; + + if (getData(element, NAMESPACE)) { + return; + } + + setData(element, NAMESPACE, this); + + if (tagName === 'img') { + this.isImg = true; + + // e.g.: "img/picture.jpg" + url = element.getAttribute('src') || ''; + this.originalUrl = url; + + // Stop when it's a blank image + if (!url) { + return; + } + + // e.g.: "http://example.com/img/picture.jpg" + url = element.src; + } else if (tagName === 'canvas' && window.HTMLCanvasElement) { + url = element.toDataURL(); + } + + this.load(url); + } + }, { + key: 'load', + value: function load(url) { + var _this = this; + + if (!url) { + return; + } + + this.url = url; + this.imageData = {}; + + var element = this.element, + options = this.options; + + + if (!options.checkOrientation || !window.ArrayBuffer) { + this.clone(); + return; + } + + // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari + if (REGEXP_DATA_URL.test(url)) { + if (REGEXP_DATA_URL_JPEG.test(url)) { + this.read(dataURLToArrayBuffer(url)); + } else { + this.clone(); + } + + return; + } + + var xhr = new XMLHttpRequest(); + + xhr.onerror = function () { + _this.clone(); + }; + + xhr.onload = function () { + _this.read(xhr.response); + }; + + if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) { + url = addTimestamp(url); + } + + xhr.open('get', url); + xhr.responseType = 'arraybuffer'; + xhr.withCredentials = element.crossOrigin === 'use-credentials'; + xhr.send(); + } + }, { + key: 'read', + value: function read(arrayBuffer) { + var options = this.options, + imageData = this.imageData; + + var orientation = getOrientation(arrayBuffer); + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + if (orientation > 1) { + this.url = arrayBufferToDataURL(arrayBuffer, 'image/jpeg'); + + var _parseOrientation = parseOrientation(orientation); + + rotate = _parseOrientation.rotate; + scaleX = _parseOrientation.scaleX; + scaleY = _parseOrientation.scaleY; + } + + if (options.rotatable) { + imageData.rotate = rotate; + } + + if (options.scalable) { + imageData.scaleX = scaleX; + imageData.scaleY = scaleY; + } + + this.clone(); + } + }, { + key: 'clone', + value: function clone() { + var element = this.element, + url = this.url; + + var crossOrigin = void 0; + var crossOriginUrl = void 0; + + if (this.options.checkCrossOrigin && isCrossOriginURL(url)) { + crossOrigin = element.crossOrigin; + + + if (crossOrigin) { + crossOriginUrl = url; + } else { + crossOrigin = 'anonymous'; + + // Bust cache when there is not a "crossOrigin" property + crossOriginUrl = addTimestamp(url); + } + } + + this.crossOrigin = crossOrigin; + this.crossOriginUrl = crossOriginUrl; + + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = crossOriginUrl || url; + + var start = proxy(this.start, this); + var stop = proxy(this.stop, this); + + this.image = image; + this.onStart = start; + this.onStop = stop; + + if (this.isImg) { + if (element.complete) { + this.start(); + } else { + addListener(element, EVENT_LOAD, start); + } + } else { + addListener(image, EVENT_LOAD, start); + addListener(image, EVENT_ERROR, stop); + addClass(image, CLASS_HIDE); + element.parentNode.insertBefore(image, element.nextSibling); + } + } + }, { + key: 'start', + value: function start(event) { + var _this2 = this; + + var image = this.isImg ? this.element : this.image; + + if (event) { + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + } + + getImageNaturalSizes(image, function (naturalWidth, naturalHeight) { + extend(_this2.imageData, { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: naturalWidth / naturalHeight + }); + _this2.loaded = true; + _this2.build(); + }); + } + }, { + key: 'stop', + value: function stop() { + var image = this.image; + + + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + image.parentNode.removeChild(image); + this.image = null; + } + }, { + key: 'build', + value: function build() { + var _this3 = this; + + if (!this.loaded) { + return; + } + + // Unbuild first when replace + if (this.ready) { + this.unbuild(); + } + + var element = this.element, + options = this.options, + image = this.image; + + // Create cropper elements + + var container = element.parentNode; + var template = document.createElement('div'); + + template.innerHTML = TEMPLATE; + + var cropper = template.querySelector('.' + NAMESPACE + '-container'); + var canvas = cropper.querySelector('.' + NAMESPACE + '-canvas'); + var dragBox = cropper.querySelector('.' + NAMESPACE + '-drag-box'); + var cropBox = cropper.querySelector('.' + NAMESPACE + '-crop-box'); + var face = cropBox.querySelector('.' + NAMESPACE + '-face'); + + this.container = container; + this.cropper = cropper; + this.canvas = canvas; + this.dragBox = dragBox; + this.cropBox = cropBox; + this.viewBox = cropper.querySelector('.' + NAMESPACE + '-view-box'); + this.face = face; + + canvas.appendChild(image); + + // Hide the original image + addClass(element, CLASS_HIDDEN); + + // Inserts the cropper after to the current image + container.insertBefore(cropper, element.nextSibling); + + // Show the image if is hidden + if (!this.isImg) { + removeClass(image, CLASS_HIDE); + } + + this.initPreview(); + this.bind(); + + options.aspectRatio = Math.max(0, options.aspectRatio) || NaN; + options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0; + + this.cropped = options.autoCrop; + + if (options.autoCrop) { + if (options.modal) { + addClass(dragBox, CLASS_MODAL); + } + } else { + addClass(cropBox, CLASS_HIDDEN); + } + + if (!options.guides) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-dashed'), CLASS_HIDDEN); + } + + if (!options.center) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-center'), CLASS_HIDDEN); + } + + if (options.background) { + addClass(cropper, NAMESPACE + '-bg'); + } + + if (!options.highlight) { + addClass(face, CLASS_INVISIBLE); + } + + if (options.cropBoxMovable) { + addClass(face, CLASS_MOVE); + setData(face, DATA_ACTION, ACTION_ALL); + } + + if (!options.cropBoxResizable) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-line'), CLASS_HIDDEN); + addClass(cropBox.getElementsByClassName(NAMESPACE + '-point'), CLASS_HIDDEN); + } + + this.setDragMode(options.dragMode); + this.render(); + this.ready = true; + this.setData(options.data); + + // Call the "ready" option asynchronously to keep "image.cropper" is defined + this.completing = setTimeout(function () { + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, { + once: true + }); + } + + dispatchEvent(element, EVENT_READY); + dispatchEvent(element, EVENT_CROP, _this3.getData()); + + _this3.complete = true; + }, 0); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.ready) { + return; + } + + if (!this.complete) { + clearTimeout(this.completing); + } + + this.ready = false; + this.complete = false; + this.initialImageData = null; + + // Clear `initialCanvasData` is necessary when replace + this.initialCanvasData = null; + this.initialCropBoxData = null; + this.containerData = null; + this.canvasData = null; + + // Clear `cropBoxData` is necessary when replace + this.cropBoxData = null; + this.unbind(); + this.resetPreview(); + this.previews = null; + this.viewBox = null; + this.cropBox = null; + this.dragBox = null; + this.canvas = null; + this.container = null; + this.cropper.parentNode.removeChild(this.cropper); + this.cropper = null; + } + + /** + * Get the no conflict cropper class. + * @returns {Cropper} The cropper class. + */ + + }], [{ + key: 'noConflict', + value: function noConflict() { + window.Cropper = AnotherCropper; + return Cropper; + } + + /** + * Change the default options. + * @param {Object} options - The new default options. + */ + + }, { + key: 'setDefaults', + value: function setDefaults(options) { + extend(DEFAULTS, isPlainObject(options) && options); + } + }]); + return Cropper; +}(); + +extend(Cropper.prototype, render, preview, events, handlers, change, methods); + +module.exports = Cropper; diff --git a/library/cropperjs/dist/cropper.css b/library/cropperjs/dist/cropper.css new file mode 100644 index 000000000..dd22178fe --- /dev/null +++ b/library/cropperjs/dist/cropper.css @@ -0,0 +1,306 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:26:29.610Z + */ + +.cropper-container { + direction: ltr; + font-size: 0; + line-height: 0; + position: relative; + -ms-touch-action: none; + touch-action: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.cropper-container img {/*Avoid margin top issue (Occur only when margin-top <= -height) + */ + display: block; + height: 100%; + image-orientation: 0deg; + max-height: none !important; + max-width: none !important; + min-height: 0 !important; + min-width: 0 !important; + width: 100%; +} + +.cropper-wrap-box, +.cropper-canvas, +.cropper-drag-box, +.cropper-crop-box, +.cropper-modal { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.cropper-wrap-box, +.cropper-canvas { + overflow: hidden; +} + +.cropper-drag-box { + background-color: #fff; + opacity: 0; +} + +.cropper-modal { + background-color: #000; + opacity: .5; +} + +.cropper-view-box { + display: block; + height: 100%; + outline-color: rgba(51, 153, 255, 0.75); + outline: 1px solid #39f; + overflow: hidden; + width: 100%; +} + +.cropper-dashed { + border: 0 dashed #eee; + display: block; + opacity: .5; + position: absolute; +} + +.cropper-dashed.dashed-h { + border-bottom-width: 1px; + border-top-width: 1px; + height: 33.33333%; + left: 0; + top: 33.33333%; + width: 100%; +} + +.cropper-dashed.dashed-v { + border-left-width: 1px; + border-right-width: 1px; + height: 100%; + left: 33.33333%; + top: 0; + width: 33.33333%; +} + +.cropper-center { + display: block; + height: 0; + left: 50%; + opacity: .75; + position: absolute; + top: 50%; + width: 0; +} + +.cropper-center:before, +.cropper-center:after { + background-color: #eee; + content: ' '; + display: block; + position: absolute; +} + +.cropper-center:before { + height: 1px; + left: -3px; + top: 0; + width: 7px; +} + +.cropper-center:after { + height: 7px; + left: 0; + top: -3px; + width: 1px; +} + +.cropper-face, +.cropper-line, +.cropper-point { + display: block; + height: 100%; + opacity: .1; + position: absolute; + width: 100%; +} + +.cropper-face { + background-color: #fff; + left: 0; + top: 0; +} + +.cropper-line { + background-color: #39f; +} + +.cropper-line.line-e { + cursor: ew-resize; + right: -3px; + top: 0; + width: 5px; +} + +.cropper-line.line-n { + cursor: ns-resize; + height: 5px; + left: 0; + top: -3px; +} + +.cropper-line.line-w { + cursor: ew-resize; + left: -3px; + top: 0; + width: 5px; +} + +.cropper-line.line-s { + bottom: -3px; + cursor: ns-resize; + height: 5px; + left: 0; +} + +.cropper-point { + background-color: #39f; + height: 5px; + opacity: .75; + width: 5px; +} + +.cropper-point.point-e { + cursor: ew-resize; + margin-top: -3px; + right: -3px; + top: 50%; +} + +.cropper-point.point-n { + cursor: ns-resize; + left: 50%; + margin-left: -3px; + top: -3px; +} + +.cropper-point.point-w { + cursor: ew-resize; + left: -3px; + margin-top: -3px; + top: 50%; +} + +.cropper-point.point-s { + bottom: -3px; + cursor: s-resize; + left: 50%; + margin-left: -3px; +} + +.cropper-point.point-ne { + cursor: nesw-resize; + right: -3px; + top: -3px; +} + +.cropper-point.point-nw { + cursor: nwse-resize; + left: -3px; + top: -3px; +} + +.cropper-point.point-sw { + bottom: -3px; + cursor: nesw-resize; + left: -3px; +} + +.cropper-point.point-se { + bottom: -3px; + cursor: nwse-resize; + height: 20px; + opacity: 1; + right: -3px; + width: 20px; +} + +@media (min-width: 768px) { + .cropper-point.point-se { + height: 15px; + width: 15px; + } +} + +@media (min-width: 992px) { + .cropper-point.point-se { + height: 10px; + width: 10px; + } +} + +@media (min-width: 1200px) { + .cropper-point.point-se { + height: 5px; + opacity: .75; + width: 5px; + } +} + +.cropper-point.point-se:before { + background-color: #39f; + bottom: -50%; + content: ' '; + display: block; + height: 200%; + opacity: 0; + position: absolute; + right: -50%; + width: 200%; +} + +.cropper-invisible { + opacity: 0; +} + +.cropper-bg { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC'); +} + +.cropper-hide { + display: block; + height: 0; + position: absolute; + width: 0; +} + +.cropper-hidden { + display: none !important; +} + +.cropper-move { + cursor: move; +} + +.cropper-crop { + cursor: crosshair; +} + +.cropper-disabled .cropper-drag-box, +.cropper-disabled .cropper-face, +.cropper-disabled .cropper-line, +.cropper-disabled .cropper-point { + cursor: not-allowed; +} + diff --git a/library/cropperjs/dist/cropper.esm.js b/library/cropperjs/dist/cropper.esm.js new file mode 100644 index 000000000..929852d8a --- /dev/null +++ b/library/cropperjs/dist/cropper.esm.js @@ -0,0 +1,3758 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:27:18.062Z + */ + +var WINDOW = typeof window !== 'undefined' ? window : {}; +var NAMESPACE = 'cropper'; + +// Actions +var ACTION_ALL = 'all'; +var ACTION_CROP = 'crop'; +var ACTION_MOVE = 'move'; +var ACTION_ZOOM = 'zoom'; +var ACTION_EAST = 'e'; +var ACTION_WEST = 'w'; +var ACTION_SOUTH = 's'; +var ACTION_NORTH = 'n'; +var ACTION_NORTH_EAST = 'ne'; +var ACTION_NORTH_WEST = 'nw'; +var ACTION_SOUTH_EAST = 'se'; +var ACTION_SOUTH_WEST = 'sw'; + +// Classes +var CLASS_CROP = NAMESPACE + '-crop'; +var CLASS_DISABLED = NAMESPACE + '-disabled'; +var CLASS_HIDDEN = NAMESPACE + '-hidden'; +var CLASS_HIDE = NAMESPACE + '-hide'; +var CLASS_INVISIBLE = NAMESPACE + '-invisible'; +var CLASS_MODAL = NAMESPACE + '-modal'; +var CLASS_MOVE = NAMESPACE + '-move'; + +// Data keys +var DATA_ACTION = 'action'; +var DATA_PREVIEW = 'preview'; + +// Drag modes +var DRAG_MODE_CROP = 'crop'; +var DRAG_MODE_MOVE = 'move'; +var DRAG_MODE_NONE = 'none'; + +// Events +var EVENT_CROP = 'crop'; +var EVENT_CROP_END = 'cropend'; +var EVENT_CROP_MOVE = 'cropmove'; +var EVENT_CROP_START = 'cropstart'; +var EVENT_DBLCLICK = 'dblclick'; +var EVENT_ERROR = 'error'; +var EVENT_LOAD = 'load'; +var EVENT_POINTER_DOWN = WINDOW.PointerEvent ? 'pointerdown' : 'touchstart mousedown'; +var EVENT_POINTER_MOVE = WINDOW.PointerEvent ? 'pointermove' : 'touchmove mousemove'; +var EVENT_POINTER_UP = WINDOW.PointerEvent ? 'pointerup pointercancel' : 'touchend touchcancel mouseup'; +var EVENT_READY = 'ready'; +var EVENT_RESIZE = 'resize'; +var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; +var EVENT_ZOOM = 'zoom'; + +// RegExps +var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; +var REGEXP_DATA_URL = /^data:/; +var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/; +var REGEXP_TAG_NAME = /^(img|canvas)$/i; + +var DEFAULTS = { + // Define the view mode of the cropper + viewMode: 0, // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + dragMode: DRAG_MODE_CROP, // 'crop', 'move' or 'none' + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A selector for adding extra containers to preview + preview: '', + + // Re-render the cropper when resize the window + responsive: true, + + // Restore the cropped area after resize the window + restore: true, + + // Check if the current image is a cross-origin image + checkCrossOrigin: true, + + // Check the current image's Exif Orientation information + checkOrientation: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by dragging touch + zoomOnTouch: true, + + // Enable to zoom the image by wheeling mouse + zoomOnWheel: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + toggleDragModeOnDblclick: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + ready: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null +}; + +var TEMPLATE = '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
    ' + '
    '; + +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; +}; + + + + + + + + + + + +var classCallCheck = function (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 toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +/** + * Check if the given value is not a number. + */ +var isNaN = Number.isNaN || WINDOW.isNaN; + +/** + * Check if the given value is a number. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a number, else `false`. + */ +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +/** + * Check if the given value is undefined. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is undefined, else `false`. + */ +function isUndefined(value) { + return typeof value === 'undefined'; +} + +/** + * Check if the given value is an object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is an object, else `false`. + */ +function isObject(value) { + return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null; +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Check if the given value is a plain object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a plain object, else `false`. + */ + +function isPlainObject(value) { + if (!isObject(value)) { + return false; + } + + try { + var _constructor = value.constructor; + var prototype = _constructor.prototype; + + + return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (e) { + return false; + } +} + +/** + * Check if the given value is a function. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a function, else `false`. + */ +function isFunction(value) { + return typeof value === 'function'; +} + +/** + * Iterate the given data. + * @param {*} data - The data to iterate. + * @param {Function} callback - The process function for each element. + * @returns {*} The original data. + */ +function each(data, callback) { + if (data && isFunction(callback)) { + if (Array.isArray(data) || isNumber(data.length) /* array-like */) { + var length = data.length; + + var i = void 0; + + for (i = 0; i < length; i += 1) { + if (callback.call(data, data[i], i, data) === false) { + break; + } + } + } else if (isObject(data)) { + Object.keys(data).forEach(function (key) { + callback.call(data, data[key], key, data); + }); + } + } + + return data; +} + +/** + * Extend the given object. + * @param {*} obj - The object to be extended. + * @param {*} args - The rest objects which will be merged to the first object. + * @returns {Object} The extended object. + */ +function extend(obj) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (isObject(obj) && args.length > 0) { + if (Object.assign) { + return Object.assign.apply(Object, [obj].concat(args)); + } + + args.forEach(function (arg) { + if (isObject(arg)) { + Object.keys(arg).forEach(function (key) { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; +} + +/** + * Takes a function and returns a new one that will always have a particular context. + * @param {Function} fn - The target function. + * @param {Object} context - The new context for the function. + * @returns {boolean} The new function. + */ +function proxy(fn, context) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; + } + + return function () { + for (var _len3 = arguments.length, args2 = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args2[_key3] = arguments[_key3]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +var REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/i; + +/** + * Normalize decimal number. + * Check out {@link http://0.30000000000000004.com/ } + * @param {number} value - The value to normalize. + * @param {number} [times=100000000000] - The times for normalizing. + * @returns {number} Returns the normalized number. + */ +function normalizeDecimalNumber(value) { + var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000; + + return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value; +} + +var REGEXP_SUFFIX = /^(width|height|left|top|marginLeft|marginTop)$/; + +/** + * Apply styles to the given element. + * @param {Element} element - The target element. + * @param {Object} styles - The styles for applying. + */ +function setStyle(element, styles) { + var style = element.style; + + + each(styles, function (value, property) { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); +} + +/** + * Check if the given element has a special class. + * @param {Element} element - The element to check. + * @param {string} value - The class to search. + * @returns {boolean} Returns `true` if the special class was found. + */ +function hasClass(element, value) { + return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1; +} + +/** + * Add classes to the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be added. + */ +function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + var className = element.className.trim(); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = className + ' ' + value; + } +} + +/** + * Remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be removed. + */ +function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } +} + +/** + * Add or remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be toggled. + * @param {boolean} added - Add only. + */ +function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + toggleClass(elem, value, added); + }); + return; + } + + // IE10-11 doesn't support the second parameter of `classList.toggle` + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } +} + +var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; + +/** + * Hyphenate the given value. + * @param {string} value - The value to hyphenate. + * @returns {string} The hyphenated value. + */ +function hyphenate(value) { + return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); +} + +/** + * Get data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to get. + * @returns {string} The data value. + */ +function getData(element, name) { + if (isObject(element[name])) { + return element[name]; + } else if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute('data-' + hyphenate(name)); +} + +/** + * Set data to the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to set. + * @param {string} data - The data value. + */ +function setData(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute('data-' + hyphenate(name), data); + } +} + +/** + * Remove data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to remove. + */ +function removeData(element, name) { + if (isObject(element[name])) { + try { + delete element[name]; + } catch (e) { + element[name] = null; + } + } else if (element.dataset) { + // #128 Safari not allows to delete dataset property + try { + delete element.dataset[name]; + } catch (e) { + element.dataset[name] = null; + } + } else { + element.removeAttribute('data-' + hyphenate(name)); + } +} + +var REGEXP_SPACES = /\s+/; + +/** + * Remove event listener from the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function removeListener(element, type, listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + removeListener(element, t, listener, options); + }); + return; + } + + if (element.removeEventListener) { + element.removeEventListener(type, listener, options); + } else if (element.detachEvent) { + element.detachEvent('on' + type, listener); + } +} + +/** + * Add event listener to the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function addListener(element, type, _listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(_listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + addListener(element, t, _listener, options); + }); + return; + } + + if (options.once) { + var originalListener = _listener; + + _listener = function listener() { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + removeListener(element, type, _listener, options); + return originalListener.apply(element, args); + }; + } + + if (element.addEventListener) { + element.addEventListener(type, _listener, options); + } else if (element.attachEvent) { + element.attachEvent('on' + type, _listener); + } +} + +/** + * Dispatch event on the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Object} data - The additional event data. + * @returns {boolean} Indicate if the event is default prevented or not. + */ +function dispatchEvent(element, type, data) { + if (element.dispatchEvent) { + var event = void 0; + + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (isFunction(Event) && isFunction(CustomEvent)) { + if (isUndefined(data)) { + event = new Event(type, { + bubbles: true, + cancelable: true + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } + } else if (isUndefined(data)) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent('on' + type); + } + + return true; +} + +/** + * Get the offset base on the document. + * @param {Element} element - The target element. + * @returns {Object} The offset data. + */ +function getOffset(element) { + var doc = document.documentElement; + var box = element.getBoundingClientRect(); + + return { + left: box.left + ((window.scrollX || doc && doc.scrollLeft || 0) - (doc && doc.clientLeft || 0)), + top: box.top + ((window.scrollY || doc && doc.scrollTop || 0) - (doc && doc.clientTop || 0)) + }; +} + +/** + * Empty an element. + * @param {Element} element - The element to empty. + */ +function empty(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +var location = WINDOW.location; + +var REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i; + +/** + * Check if the given URL is a cross origin URL. + * @param {string} url - The target URL. + * @returns {boolean} Returns `true` if the given URL is a cross origin URL, else `false`. + */ +function isCrossOriginURL(url) { + var parts = url.match(REGEXP_ORIGINS); + + return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port); +} + +/** + * Add timestamp to the given URL. + * @param {string} url - The target URL. + * @returns {string} The result URL. + */ +function addTimestamp(url) { + var timestamp = 'timestamp=' + new Date().getTime(); + + return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp; +} + +/** + * Get transforms base on the given object. + * @param {Object} obj - The target object. + * @returns {string} A string contains transform values. + */ +function getTransforms(_ref) { + var rotate = _ref.rotate, + scaleX = _ref.scaleX, + scaleY = _ref.scaleY, + translateX = _ref.translateX, + translateY = _ref.translateY; + + var values = []; + + if (isNumber(translateX) && translateX !== 0) { + values.push('translateX(' + translateX + 'px)'); + } + + if (isNumber(translateY) && translateY !== 0) { + values.push('translateY(' + translateY + 'px)'); + } + + // Rotate should come first before scale to match orientation transform + if (isNumber(rotate) && rotate !== 0) { + values.push('rotate(' + rotate + 'deg)'); + } + + if (isNumber(scaleX) && scaleX !== 1) { + values.push('scaleX(' + scaleX + ')'); + } + + if (isNumber(scaleY) && scaleY !== 1) { + values.push('scaleY(' + scaleY + ')'); + } + + var transform = values.length ? values.join(' ') : 'none'; + + return { + WebkitTransform: transform, + msTransform: transform, + transform: transform + }; +} + +var navigator = WINDOW.navigator; + +var IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent); + +/** + * Get an image's natural sizes. + * @param {string} image - The target image. + * @param {Function} callback - The callback function. + */ +function getImageNaturalSizes(image, callback) { + // Modern browsers (except Safari) + if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) { + callback(image.naturalWidth, image.naturalHeight); + return; + } + + var newImage = document.createElement('img'); + var body = document.body || document.documentElement; + + newImage.onload = function () { + callback(newImage.width, newImage.height); + + if (!IS_SAFARI_OR_UIWEBVIEW) { + body.removeChild(newImage); + } + }; + + newImage.src = image.src; + + // iOS Safari will convert the image automatically + // with its orientation once append it into DOM (#279) + if (!IS_SAFARI_OR_UIWEBVIEW) { + newImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;'; + body.appendChild(newImage); + } +} + +/** + * Get the max ratio of a group of pointers. + * @param {string} pointers - The target pointers. + * @returns {number} The result ratio. + */ +function getMaxZoomRatio(pointers) { + var pointers2 = extend({}, pointers); + var ratios = []; + + each(pointers, function (pointer, pointerId) { + delete pointers2[pointerId]; + + each(pointers2, function (pointer2) { + var x1 = Math.abs(pointer.startX - pointer2.startX); + var y1 = Math.abs(pointer.startY - pointer2.startY); + var x2 = Math.abs(pointer.endX - pointer2.endX); + var y2 = Math.abs(pointer.endY - pointer2.endY); + var z1 = Math.sqrt(x1 * x1 + y1 * y1); + var z2 = Math.sqrt(x2 * x2 + y2 * y2); + var ratio = (z2 - z1) / z1; + + ratios.push(ratio); + }); + }); + + ratios.sort(function (a, b) { + return Math.abs(a) < Math.abs(b); + }); + + return ratios[0]; +} + +/** + * Get a pointer from an event object. + * @param {Object} event - The target event object. + * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not. + * @returns {Object} The result pointer contains start and/or end point coordinates. + */ +function getPointer(_ref2, endOnly) { + var pageX = _ref2.pageX, + pageY = _ref2.pageY; + + var end = { + endX: pageX, + endY: pageY + }; + + if (endOnly) { + return end; + } + + return extend({ + startX: pageX, + startY: pageY + }, end); +} + +/** + * Get the center point coordinate of a group of pointers. + * @param {Object} pointers - The target pointers. + * @returns {Object} The center point coordinate. + */ +function getPointersCenter(pointers) { + var pageX = 0; + var pageY = 0; + var count = 0; + + each(pointers, function (_ref3) { + var startX = _ref3.startX, + startY = _ref3.startY; + + pageX += startX; + pageY += startY; + count += 1; + }); + + pageX /= count; + pageY /= count; + + return { + pageX: pageX, + pageY: pageY + }; +} + +/** + * Check if the given value is a finite number. + */ +var isFinite = Number.isFinite || WINDOW.isFinite; + +/** + * Get the max sizes in a rectangle under the given aspect ratio. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getContainSizes(_ref4) { + var aspectRatio = _ref4.aspectRatio, + height = _ref4.height, + width = _ref4.width; + + var isValidNumber = function isValidNumber(value) { + return isFinite(value) && value > 0; + }; + + if (isValidNumber(width) && isValidNumber(height)) { + if (height * aspectRatio > width) { + height = width / aspectRatio; + } else { + width = height * aspectRatio; + } + } else if (isValidNumber(width)) { + height = width / aspectRatio; + } else if (isValidNumber(height)) { + width = height * aspectRatio; + } + + return { + width: width, + height: height + }; +} + +/** + * Get the new sizes of a rectangle after rotated. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getRotatedSizes(_ref5) { + var width = _ref5.width, + height = _ref5.height, + degree = _ref5.degree; + + degree = Math.abs(degree) % 180; + + if (degree === 90) { + return { + width: height, + height: width + }; + } + + var arc = degree % 90 * Math.PI / 180; + var sinArc = Math.sin(arc); + var cosArc = Math.cos(arc); + var newWidth = width * cosArc + height * sinArc; + var newHeight = width * sinArc + height * cosArc; + + return degree > 90 ? { + width: newHeight, + height: newWidth + } : { + width: newWidth, + height: newHeight + }; +} + +/** + * Get a canvas which drew the given image. + * @param {HTMLImageElement} image - The image for drawing. + * @param {Object} imageData - The image data. + * @param {Object} canvasData - The canvas data. + * @param {Object} options - The options. + * @returns {HTMLCanvasElement} The result canvas. + */ +function getSourceCanvas(image, _ref6, _ref7, _ref8) { + var imageNaturalWidth = _ref6.naturalWidth, + imageNaturalHeight = _ref6.naturalHeight, + _ref6$rotate = _ref6.rotate, + rotate = _ref6$rotate === undefined ? 0 : _ref6$rotate, + _ref6$scaleX = _ref6.scaleX, + scaleX = _ref6$scaleX === undefined ? 1 : _ref6$scaleX, + _ref6$scaleY = _ref6.scaleY, + scaleY = _ref6$scaleY === undefined ? 1 : _ref6$scaleY; + var aspectRatio = _ref7.aspectRatio, + naturalWidth = _ref7.naturalWidth, + naturalHeight = _ref7.naturalHeight; + var _ref8$fillColor = _ref8.fillColor, + fillColor = _ref8$fillColor === undefined ? 'transparent' : _ref8$fillColor, + _ref8$imageSmoothingE = _ref8.imageSmoothingEnabled, + imageSmoothingEnabled = _ref8$imageSmoothingE === undefined ? true : _ref8$imageSmoothingE, + _ref8$imageSmoothingQ = _ref8.imageSmoothingQuality, + imageSmoothingQuality = _ref8$imageSmoothingQ === undefined ? 'low' : _ref8$imageSmoothingQ, + _ref8$maxWidth = _ref8.maxWidth, + maxWidth = _ref8$maxWidth === undefined ? Infinity : _ref8$maxWidth, + _ref8$maxHeight = _ref8.maxHeight, + maxHeight = _ref8$maxHeight === undefined ? Infinity : _ref8$maxHeight, + _ref8$minWidth = _ref8.minWidth, + minWidth = _ref8$minWidth === undefined ? 0 : _ref8$minWidth, + _ref8$minHeight = _ref8.minHeight, + minHeight = _ref8$minHeight === undefined ? 0 : _ref8$minHeight; + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: maxWidth, + height: maxHeight + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minWidth, + height: minHeight + }); + var width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth)); + var height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight)); + var params = [-imageNaturalWidth / 2, -imageNaturalHeight / 2, imageNaturalWidth, imageNaturalHeight]; + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + context.fillStyle = fillColor; + context.fillRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + context.rotate(rotate * Math.PI / 180); + context.scale(scaleX, scaleY); + context.imageSmoothingEnabled = imageSmoothingEnabled; + context.imageSmoothingQuality = imageSmoothingQuality; + context.drawImage.apply(context, [image].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + context.restore(); + return canvas; +} + +var fromCharCode = String.fromCharCode; + +/** + * Get string from char code in data view. + * @param {DataView} dataView - The data view for read. + * @param {number} start - The start index. + * @param {number} length - The read length. + * @returns {string} The read result. + */ + +function getStringFromCharCode(dataView, start, length) { + var str = ''; + var i = void 0; + + length += start; + + for (i = start; i < length; i += 1) { + str += fromCharCode(dataView.getUint8(i)); + } + + return str; +} + +var REGEXP_DATA_URL_HEAD = /^data:.*,/; + +/** + * Transform Data URL to array buffer. + * @param {string} dataURL - The Data URL to transform. + * @returns {ArrayBuffer} The result array buffer. + */ +function dataURLToArrayBuffer(dataURL) { + var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); + var binary = atob(base64); + var arrayBuffer = new ArrayBuffer(binary.length); + var uint8 = new Uint8Array(arrayBuffer); + + each(uint8, function (value, i) { + uint8[i] = binary.charCodeAt(i); + }); + + return arrayBuffer; +} + +/** + * Transform array buffer to Data URL. + * @param {ArrayBuffer} arrayBuffer - The array buffer to transform. + * @param {string} mimeType - The mime type of the Data URL. + * @returns {string} The result Data URL. + */ +function arrayBufferToDataURL(arrayBuffer, mimeType) { + var uint8 = new Uint8Array(arrayBuffer); + var data = ''; + + // TypedArray.prototype.forEach is not supported in some browsers. + each(uint8, function (value) { + data += fromCharCode(value); + }); + + return 'data:' + mimeType + ';base64,' + btoa(data); +} + +/** + * Get orientation value from given array buffer. + * @param {ArrayBuffer} arrayBuffer - The array buffer to read. + * @returns {number} The read orientation value. + */ +function getOrientation(arrayBuffer) { + var dataView = new DataView(arrayBuffer); + var orientation = void 0; + var littleEndian = void 0; + var app1Start = void 0; + var ifdStart = void 0; + + // Only handle JPEG image (start by 0xFFD8) + if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { + var length = dataView.byteLength; + var offset = 2; + + while (offset < length) { + if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { + app1Start = offset; + break; + } + + offset += 1; + } + } + + if (app1Start) { + var exifIDCode = app1Start + 4; + var tiffOffset = app1Start + 10; + + if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { + var endianness = dataView.getUint16(tiffOffset); + + littleEndian = endianness === 0x4949; + + if (littleEndian || endianness === 0x4D4D /* bigEndian */) { + if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { + var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); + + if (firstIFDOffset >= 0x00000008) { + ifdStart = tiffOffset + firstIFDOffset; + } + } + } + } + } + + if (ifdStart) { + var _length = dataView.getUint16(ifdStart, littleEndian); + var _offset = void 0; + var i = void 0; + + for (i = 0; i < _length; i += 1) { + _offset = ifdStart + i * 12 + 2; + + if (dataView.getUint16(_offset, littleEndian) === 0x0112 /* Orientation */) { + // 8 is the offset of the current tag's value + _offset += 8; + + // Get the original orientation value + orientation = dataView.getUint16(_offset, littleEndian); + + // Override the orientation with its default value + dataView.setUint16(_offset, 1, littleEndian); + break; + } + } + } + + return orientation; +} + +/** + * Parse Exif Orientation value. + * @param {number} orientation - The orientation to parse. + * @returns {Object} The parsed result. + */ +function parseOrientation(orientation) { + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + switch (orientation) { + // Flip horizontal + case 2: + scaleX = -1; + break; + + // Rotate left 180° + case 3: + rotate = -180; + break; + + // Flip vertical + case 4: + scaleY = -1; + break; + + // Flip vertical and rotate right 90° + case 5: + rotate = 90; + scaleY = -1; + break; + + // Rotate right 90° + case 6: + rotate = 90; + break; + + // Flip horizontal and rotate right 90° + case 7: + rotate = 90; + scaleX = -1; + break; + + // Rotate left 90° + case 8: + rotate = -90; + break; + + default: + } + + return { + rotate: rotate, + scaleX: scaleX, + scaleY: scaleY + }; +} + +var render = { + render: function render() { + this.initContainer(); + this.initCanvas(); + this.initCropBox(); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + }, + initContainer: function initContainer() { + var element = this.element, + options = this.options, + container = this.container, + cropper = this.cropper; + + + addClass(cropper, CLASS_HIDDEN); + removeClass(element, CLASS_HIDDEN); + + var containerData = { + width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200), + height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100) + }; + + this.containerData = containerData; + + setStyle(cropper, { + width: containerData.width, + height: containerData.height + }); + + addClass(element, CLASS_HIDDEN); + removeClass(cropper, CLASS_HIDDEN); + }, + + + // Canvas (image wrapper) + initCanvas: function initCanvas() { + var containerData = this.containerData, + imageData = this.imageData; + var viewMode = this.options.viewMode; + + var rotated = Math.abs(imageData.rotate) % 180 === 90; + var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth; + var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight; + var aspectRatio = naturalWidth / naturalHeight; + var canvasWidth = containerData.width; + var canvasHeight = containerData.height; + + if (containerData.height * aspectRatio > containerData.width) { + if (viewMode === 3) { + canvasWidth = containerData.height * aspectRatio; + } else { + canvasHeight = containerData.width / aspectRatio; + } + } else if (viewMode === 3) { + canvasHeight = containerData.width / aspectRatio; + } else { + canvasWidth = containerData.height * aspectRatio; + } + + var canvasData = { + aspectRatio: aspectRatio, + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + width: canvasWidth, + height: canvasHeight + }; + + canvasData.left = (containerData.width - canvasWidth) / 2; + canvasData.top = (containerData.height - canvasHeight) / 2; + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + this.canvasData = canvasData; + this.limited = viewMode === 1 || viewMode === 2; + this.limitCanvas(true, true); + this.initialImageData = extend({}, imageData); + this.initialCanvasData = extend({}, canvasData); + }, + limitCanvas: function limitCanvas(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var viewMode = options.viewMode; + var aspectRatio = canvasData.aspectRatio; + + var cropped = this.cropped && cropBoxData; + + if (sizeLimited) { + var minCanvasWidth = Number(options.minCanvasWidth) || 0; + var minCanvasHeight = Number(options.minCanvasHeight) || 0; + + if (viewMode > 1) { + minCanvasWidth = Math.max(minCanvasWidth, containerData.width); + minCanvasHeight = Math.max(minCanvasHeight, containerData.height); + + if (viewMode === 3) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } else if (viewMode > 0) { + if (minCanvasWidth) { + minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0); + } else if (minCanvasHeight) { + minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0); + } else if (cropped) { + minCanvasWidth = cropBoxData.width; + minCanvasHeight = cropBoxData.height; + + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minCanvasWidth, + height: minCanvasHeight + }); + + minCanvasWidth = _getContainSizes.width; + minCanvasHeight = _getContainSizes.height; + + + canvasData.minWidth = minCanvasWidth; + canvasData.minHeight = minCanvasHeight; + canvasData.maxWidth = Infinity; + canvasData.maxHeight = Infinity; + } + + if (positionLimited) { + if (viewMode) { + var newCanvasLeft = containerData.width - canvasData.width; + var newCanvasTop = containerData.height - canvasData.height; + + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + canvasData.maxTop = Math.max(0, newCanvasTop); + + if (cropped && this.limited) { + canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width)); + canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height)); + canvasData.maxLeft = cropBoxData.left; + canvasData.maxTop = cropBoxData.top; + + if (viewMode === 2) { + if (canvasData.width >= containerData.width) { + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + } + + if (canvasData.height >= containerData.height) { + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxTop = Math.max(0, newCanvasTop); + } + } + } + } else { + canvasData.minLeft = -canvasData.width; + canvasData.minTop = -canvasData.height; + canvasData.maxLeft = containerData.width; + canvasData.maxTop = containerData.height; + } + } + }, + renderCanvas: function renderCanvas(changed, transformed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + + if (transformed) { + var _getRotatedSizes = getRotatedSizes({ + width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1), + height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1), + degree: imageData.rotate || 0 + }), + naturalWidth = _getRotatedSizes.width, + naturalHeight = _getRotatedSizes.height; + + var width = canvasData.width * (naturalWidth / canvasData.naturalWidth); + var height = canvasData.height * (naturalHeight / canvasData.naturalHeight); + + canvasData.left -= (width - canvasData.width) / 2; + canvasData.top -= (height - canvasData.height) / 2; + canvasData.width = width; + canvasData.height = height; + canvasData.aspectRatio = naturalWidth / naturalHeight; + canvasData.naturalWidth = naturalWidth; + canvasData.naturalHeight = naturalHeight; + this.limitCanvas(true, false); + } + + if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) { + canvasData.left = canvasData.oldLeft; + } + + if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) { + canvasData.top = canvasData.oldTop; + } + + canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth); + canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight); + + this.limitCanvas(false, true); + + canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft); + canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop); + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + setStyle(this.canvas, extend({ + width: canvasData.width, + height: canvasData.height + }, getTransforms({ + translateX: canvasData.left, + translateY: canvasData.top + }))); + + this.renderImage(changed); + + if (this.cropped && this.limited) { + this.limitCropBox(true, true); + } + }, + renderImage: function renderImage(changed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + var width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth); + var height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight); + + extend(imageData, { + width: width, + height: height, + left: (canvasData.width - width) / 2, + top: (canvasData.height - height) / 2 + }); + setStyle(this.image, extend({ + width: imageData.width, + height: imageData.height + }, getTransforms(extend({ + translateX: imageData.left, + translateY: imageData.top + }, imageData)))); + + if (changed) { + this.output(); + } + }, + initCropBox: function initCropBox() { + var options = this.options, + canvasData = this.canvasData; + var aspectRatio = options.aspectRatio; + + var autoCropArea = Number(options.autoCropArea) || 0.8; + var cropBoxData = { + width: canvasData.width, + height: canvasData.height + }; + + if (aspectRatio) { + if (canvasData.height * aspectRatio > canvasData.width) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.cropBoxData = cropBoxData; + this.limitCropBox(true, true); + + // Initialize auto crop area + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + // The width/height of auto crop area must large than "minWidth/Height" + cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea); + cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea); + cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2; + cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2; + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + this.initialCropBoxData = extend({}, cropBoxData); + }, + limitCropBox: function limitCropBox(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData, + limited = this.limited; + var aspectRatio = options.aspectRatio; + + + if (sizeLimited) { + var minCropBoxWidth = Number(options.minCropBoxWidth) || 0; + var minCropBoxHeight = Number(options.minCropBoxHeight) || 0; + var maxCropBoxWidth = Math.min(containerData.width, limited ? canvasData.width : containerData.width); + var maxCropBoxHeight = Math.min(containerData.height, limited ? canvasData.height : containerData.height); + + // The min/maxCropBoxWidth/Height must be less than container's width/height + minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width); + minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height); + + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } + } + + // The minWidth/Height must be less than maxWidth/Height + cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth); + cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight); + cropBoxData.maxWidth = maxCropBoxWidth; + cropBoxData.maxHeight = maxCropBoxHeight; + } + + if (positionLimited) { + if (limited) { + cropBoxData.minLeft = Math.max(0, canvasData.left); + cropBoxData.minTop = Math.max(0, canvasData.top); + cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width; + cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height; + } else { + cropBoxData.minLeft = 0; + cropBoxData.minTop = 0; + cropBoxData.maxLeft = containerData.width - cropBoxData.width; + cropBoxData.maxTop = containerData.height - cropBoxData.height; + } + } + }, + renderCropBox: function renderCropBox() { + var options = this.options, + containerData = this.containerData, + cropBoxData = this.cropBoxData; + + + if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) { + cropBoxData.left = cropBoxData.oldLeft; + } + + if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) { + cropBoxData.top = cropBoxData.oldTop; + } + + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + this.limitCropBox(false, true); + + cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft); + cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop); + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + if (options.movable && options.cropBoxMovable) { + // Turn to move the canvas when the crop box is equal to the container + setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width && cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL); + } + + setStyle(this.cropBox, extend({ + width: cropBoxData.width, + height: cropBoxData.height + }, getTransforms({ + translateX: cropBoxData.left, + translateY: cropBoxData.top + }))); + + if (this.cropped && this.limited) { + this.limitCanvas(true, true); + } + + if (!this.disabled) { + this.output(); + } + }, + output: function output() { + this.preview(); + + if (this.complete) { + dispatchEvent(this.element, EVENT_CROP, this.getData()); + } + } +}; + +var preview = { + initPreview: function initPreview() { + var crossOrigin = this.crossOrigin; + var preview = this.options.preview; + + var url = crossOrigin ? this.crossOriginUrl : this.url; + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = url; + this.viewBox.appendChild(image); + this.image2 = image; + + if (!preview) { + return; + } + + var previews = preview.querySelector ? [preview] : document.querySelectorAll(preview); + + this.previews = previews; + + each(previews, function (element) { + var img = document.createElement('img'); + + // Save the original size for recover + setData(element, DATA_PREVIEW, { + width: element.offsetWidth, + height: element.offsetHeight, + html: element.innerHTML + }); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * Add `height:auto` to override `height` attribute on IE8 + * (Occur only when margin-top <= -height) + */ + img.style.cssText = 'display:block;' + 'width:100%;' + 'height:auto;' + 'min-width:0!important;' + 'min-height:0!important;' + 'max-width:none!important;' + 'max-height:none!important;' + 'image-orientation:0deg!important;"'; + + empty(element); + element.appendChild(img); + }); + }, + resetPreview: function resetPreview() { + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + + setStyle(element, { + width: data.width, + height: data.height + }); + + element.innerHTML = data.html; + removeData(element, DATA_PREVIEW); + }); + }, + preview: function preview() { + var imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var cropBoxWidth = cropBoxData.width, + cropBoxHeight = cropBoxData.height; + var width = imageData.width, + height = imageData.height; + + var left = cropBoxData.left - canvasData.left - imageData.left; + var top = cropBoxData.top - canvasData.top - imageData.top; + + if (!this.cropped || this.disabled) { + return; + } + + setStyle(this.image2, extend({ + width: width, + height: height + }, getTransforms(extend({ + translateX: -left, + translateY: -top + }, imageData)))); + + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + var originalWidth = data.width; + var originalHeight = data.height; + var newWidth = originalWidth; + var newHeight = originalHeight; + var ratio = 1; + + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; + } + + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } + + setStyle(element, { + width: newWidth, + height: newHeight + }); + + setStyle(element.getElementsByTagName('img')[0], extend({ + width: width * ratio, + height: height * ratio + }, getTransforms(extend({ + translateX: -left * ratio, + translateY: -top * ratio + }, imageData)))); + }); + } +}; + +var events = { + bind: function bind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + addListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + addListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + addListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + addListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom); + } + + addListener(cropper, EVENT_POINTER_DOWN, this.onCropStart = proxy(this.cropStart, this)); + + if (options.zoomable && options.zoomOnWheel) { + addListener(cropper, EVENT_WHEEL, this.onWheel = proxy(this.wheel, this)); + } + + if (options.toggleDragModeOnDblclick) { + addListener(cropper, EVENT_DBLCLICK, this.onDblclick = proxy(this.dblclick, this)); + } + + addListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove = proxy(this.cropMove, this)); + addListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd = proxy(this.cropEnd, this)); + + if (options.responsive) { + addListener(window, EVENT_RESIZE, this.onResize = proxy(this.resize, this)); + } + }, + unbind: function unbind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + removeListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + removeListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + removeListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + removeListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + removeListener(element, EVENT_ZOOM, options.zoom); + } + + removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart); + + if (options.zoomable && options.zoomOnWheel) { + removeListener(cropper, EVENT_WHEEL, this.onWheel); + } + + if (options.toggleDragModeOnDblclick) { + removeListener(cropper, EVENT_DBLCLICK, this.onDblclick); + } + + removeListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove); + removeListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd); + + if (options.responsive) { + removeListener(window, EVENT_RESIZE, this.onResize); + } + } +}; + +var handlers = { + resize: function resize() { + var options = this.options, + container = this.container, + containerData = this.containerData; + + var minContainerWidth = Number(options.minContainerWidth) || 200; + var minContainerHeight = Number(options.minContainerHeight) || 100; + + if (this.disabled || containerData.width <= minContainerWidth || containerData.height <= minContainerHeight) { + return; + } + + var ratio = container.offsetWidth / containerData.width; + + // Resize when width changed or height changed + if (ratio !== 1 || container.offsetHeight !== containerData.height) { + var canvasData = void 0; + var cropBoxData = void 0; + + if (options.restore) { + canvasData = this.getCanvasData(); + cropBoxData = this.getCropBoxData(); + } + + this.render(); + + if (options.restore) { + this.setCanvasData(each(canvasData, function (n, i) { + canvasData[i] = n * ratio; + })); + this.setCropBoxData(each(cropBoxData, function (n, i) { + cropBoxData[i] = n * ratio; + })); + } + } + }, + dblclick: function dblclick() { + if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) { + return; + } + + this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP); + }, + wheel: function wheel(e) { + var _this = this; + + var ratio = Number(this.options.wheelZoomRatio) || 0.1; + var delta = 1; + + if (this.disabled) { + return; + } + + e.preventDefault(); + + // Limit wheel speed to prevent zoom too fast (#21) + if (this.wheeling) { + return; + } + + this.wheeling = true; + + setTimeout(function () { + _this.wheeling = false; + }, 50); + + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + this.zoom(-delta * ratio, e); + }, + cropStart: function cropStart(e) { + if (this.disabled) { + return; + } + + var options = this.options, + pointers = this.pointers; + + var action = void 0; + + if (e.changedTouches) { + // Handle touch event + each(e.changedTouches, function (touch) { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + // Handle mouse event and pointer event + pointers[e.pointerId || 0] = getPointer(e); + } + + if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { + action = ACTION_ZOOM; + } else { + action = getData(e.target, DATA_ACTION); + } + + if (!REGEXP_ACTIONS.test(action)) { + return; + } + + if (dispatchEvent(this.element, EVENT_CROP_START, { + originalEvent: e, + action: action + }) === false) { + return; + } + + e.preventDefault(); + + this.action = action; + this.cropping = false; + + if (action === ACTION_CROP) { + this.cropping = true; + addClass(this.dragBox, CLASS_MODAL); + } + }, + cropMove: function cropMove(e) { + var action = this.action; + + + if (this.disabled || !action) { + return; + } + + var pointers = this.pointers; + + + e.preventDefault(); + + if (dispatchEvent(this.element, EVENT_CROP_MOVE, { + originalEvent: e, + action: action + }) === false) { + return; + } + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + extend(pointers[touch.identifier], getPointer(touch, true)); + }); + } else { + extend(pointers[e.pointerId || 0], getPointer(e, true)); + } + + this.change(e); + }, + cropEnd: function cropEnd(e) { + if (this.disabled) { + return; + } + + var action = this.action, + pointers = this.pointers; + + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + delete pointers[touch.identifier]; + }); + } else { + delete pointers[e.pointerId || 0]; + } + + if (!action) { + return; + } + + e.preventDefault(); + + if (!Object.keys(pointers).length) { + this.action = ''; + } + + if (this.cropping) { + this.cropping = false; + toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal); + } + + dispatchEvent(this.element, EVENT_CROP_END, { + originalEvent: e, + action: action + }); + } +}; + +var change = { + change: function change(e) { + var options = this.options, + canvasData = this.canvasData, + containerData = this.containerData, + cropBoxData = this.cropBoxData, + pointers = this.pointers; + var action = this.action; + var aspectRatio = options.aspectRatio; + var left = cropBoxData.left, + top = cropBoxData.top, + width = cropBoxData.width, + height = cropBoxData.height; + + var right = left + width; + var bottom = top + height; + var minLeft = 0; + var minTop = 0; + var maxWidth = containerData.width; + var maxHeight = containerData.height; + var renderable = true; + var offset = void 0; + + // Locking aspect ratio in "free mode" by holding shift key + if (!aspectRatio && e.shiftKey) { + aspectRatio = width && height ? width / height : 1; + } + + if (this.limited) { + minLeft = cropBoxData.minLeft; + minTop = cropBoxData.minTop; + + maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width); + maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height); + } + + var pointer = pointers[Object.keys(pointers)[0]]; + var range = { + x: pointer.endX - pointer.startX, + y: pointer.endY - pointer.startY + }; + var check = function check(side) { + switch (side) { + case ACTION_EAST: + if (right + range.x > maxWidth) { + range.x = maxWidth - right; + } + + break; + + case ACTION_WEST: + if (left + range.x < minLeft) { + range.x = minLeft - left; + } + + break; + + case ACTION_NORTH: + if (top + range.y < minTop) { + range.y = minTop - top; + } + + break; + + case ACTION_SOUTH: + if (bottom + range.y > maxHeight) { + range.y = maxHeight - bottom; + } + + break; + + default: + } + }; + + switch (action) { + // Move crop box + case ACTION_ALL: + left += range.x; + top += range.y; + break; + + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_WEST; + width = 0; + } + + break; + + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_SOUTH; + height = 0; + } + + break; + + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_EAST; + width = 0; + } + + break; + + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_SOUTH); + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_NORTH; + height = 0; + } + + break; + + case ACTION_NORTH_EAST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + } + + break; + + case ACTION_NORTH_WEST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.y * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_WEST: + if (aspectRatio) { + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_EAST: + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + } + + break; + + // Move canvas + case ACTION_MOVE: + this.move(range.x, range.y); + renderable = false; + break; + + // Zoom canvas + case ACTION_ZOOM: + this.zoom(getMaxZoomRatio(pointers), e); + renderable = false; + break; + + // Create crop box + case ACTION_CROP: + if (!range.x || !range.y) { + renderable = false; + break; + } + + offset = getOffset(this.cropper); + left = pointer.startX - offset.left; + top = pointer.startY - offset.top; + width = cropBoxData.minWidth; + height = cropBoxData.minHeight; + + if (range.x > 0) { + action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; + } else if (range.x < 0) { + left -= width; + action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; + } + + if (range.y < 0) { + top -= height; + } + + // Show the crop box if is hidden + if (!this.cropped) { + removeClass(this.cropBox, CLASS_HIDDEN); + this.cropped = true; + + if (this.limited) { + this.limitCropBox(true, true); + } + } + + break; + + default: + } + + if (renderable) { + cropBoxData.width = width; + cropBoxData.height = height; + cropBoxData.left = left; + cropBoxData.top = top; + this.action = action; + this.renderCropBox(); + } + + // Override + each(pointers, function (p) { + p.startX = p.endX; + p.startY = p.endY; + }); + } +}; + +var methods = { + // Show the crop box manually + crop: function crop() { + if (this.ready && !this.disabled) { + if (!this.cropped) { + this.cropped = true; + this.limitCropBox(true, true); + + if (this.options.modal) { + addClass(this.dragBox, CLASS_MODAL); + } + + removeClass(this.cropBox, CLASS_HIDDEN); + } + + this.setCropBoxData(this.initialCropBoxData); + } + + return this; + }, + + + // Reset the image and crop box to their initial states + reset: function reset() { + if (this.ready && !this.disabled) { + this.imageData = extend({}, this.initialImageData); + this.canvasData = extend({}, this.initialCanvasData); + this.cropBoxData = extend({}, this.initialCropBoxData); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + } + + return this; + }, + + + // Clear the crop box + clear: function clear() { + if (this.cropped && !this.disabled) { + extend(this.cropBoxData, { + left: 0, + top: 0, + width: 0, + height: 0 + }); + + this.cropped = false; + this.renderCropBox(); + this.limitCanvas(true, true); + + // Render canvas after crop box rendered + this.renderCanvas(); + removeClass(this.dragBox, CLASS_MODAL); + addClass(this.cropBox, CLASS_HIDDEN); + } + + return this; + }, + + + /** + * Replace the image's src and rebuild the cropper + * @param {string} url - The new URL. + * @param {boolean} [onlyColorChanged] - Indicate if the new image only changed color. + * @returns {Object} this + */ + replace: function replace(url) { + var onlyColorChanged = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!this.disabled && url) { + if (this.isImg) { + this.element.src = url; + } + + if (onlyColorChanged) { + this.url = url; + this.image.src = url; + + if (this.ready) { + this.image2.src = url; + + each(this.previews, function (element) { + element.getElementsByTagName('img')[0].src = url; + }); + } + } else { + if (this.isImg) { + this.replaced = true; + } + + // Clear previous data + this.options.data = null; + this.load(url); + } + } + + return this; + }, + + + // Enable (unfreeze) the cropper + enable: function enable() { + if (this.ready) { + this.disabled = false; + removeClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Disable (freeze) the cropper + disable: function disable() { + if (this.ready) { + this.disabled = true; + addClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Destroy the cropper and remove the instance from the image + destroy: function destroy() { + var element = this.element, + image = this.image; + + + if (this.loaded) { + if (this.isImg && this.replaced) { + element.src = this.originalUrl; + } + + this.unbuild(); + removeClass(element, CLASS_HIDDEN); + } else if (this.isImg) { + removeListener(element, EVENT_LOAD, this.onStart); + } else if (image) { + image.parentNode.removeChild(image); + } + + removeData(element, NAMESPACE); + + return this; + }, + + + /** + * Move the canvas with relative offsets + * @param {number} offsetX - The relative offset distance on the x-axis. + * @param {number} offsetY - The relative offset distance on the y-axis. + * @returns {Object} this + */ + move: function move(offsetX, offsetY) { + var _canvasData = this.canvasData, + left = _canvasData.left, + top = _canvasData.top; + + + return this.moveTo(isUndefined(offsetX) ? offsetX : left + Number(offsetX), isUndefined(offsetY) ? offsetY : top + Number(offsetY)); + }, + + + /** + * Move the canvas to an absolute point + * @param {number} x - The x-axis coordinate. + * @param {number} [y=x] - The y-axis coordinate. + * @returns {Object} this + */ + moveTo: function moveTo(x) { + var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x; + var canvasData = this.canvasData; + + var changed = false; + + x = Number(x); + y = Number(y); + + if (this.ready && !this.disabled && this.options.movable) { + if (isNumber(x)) { + canvasData.left = x; + changed = true; + } + + if (isNumber(y)) { + canvasData.top = y; + changed = true; + } + + if (changed) { + this.renderCanvas(true); + } + } + + return this; + }, + + + /** + * Zoom the canvas with a relative ratio + * @param {number} ratio - The target ratio. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoom: function zoom(ratio, _originalEvent) { + var canvasData = this.canvasData; + + + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + return this.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, null, _originalEvent); + }, + + + /** + * Zoom the canvas to an absolute ratio + * @param {number} ratio - The target ratio. + * @param {Object} pivot - The zoom pivot point coordinate. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoomTo: function zoomTo(ratio, pivot, _originalEvent) { + var options = this.options, + canvasData = this.canvasData; + var width = canvasData.width, + height = canvasData.height, + naturalWidth = canvasData.naturalWidth, + naturalHeight = canvasData.naturalHeight; + + + ratio = Number(ratio); + + if (ratio >= 0 && this.ready && !this.disabled && options.zoomable) { + var newWidth = naturalWidth * ratio; + var newHeight = naturalHeight * ratio; + + if (dispatchEvent(this.element, EVENT_ZOOM, { + originalEvent: _originalEvent, + oldRatio: width / naturalWidth, + ratio: newWidth / naturalWidth + }) === false) { + return this; + } + + if (_originalEvent) { + var pointers = this.pointers; + + var offset = getOffset(this.cropper); + var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY + }; + + // Zoom from the triggering point of the event + canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height); + } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) { + canvasData.left -= (newWidth - width) * ((pivot.x - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((pivot.y - canvasData.top) / height); + } else { + // Zoom from the center of the canvas + canvasData.left -= (newWidth - width) / 2; + canvasData.top -= (newHeight - height) / 2; + } + + canvasData.width = newWidth; + canvasData.height = newHeight; + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Rotate the canvas with a relative degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotate: function rotate(degree) { + return this.rotateTo((this.imageData.rotate || 0) + Number(degree)); + }, + + + /** + * Rotate the canvas to an absolute degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotateTo: function rotateTo(degree) { + degree = Number(degree); + + if (isNumber(degree) && this.ready && !this.disabled && this.options.rotatable) { + this.imageData.rotate = degree % 360; + this.renderCanvas(true, true); + } + + return this; + }, + + + /** + * Scale the image on the x-axis. + * @param {number} scaleX - The scale ratio on the x-axis. + * @returns {Object} this + */ + scaleX: function scaleX(_scaleX) { + var scaleY = this.imageData.scaleY; + + + return this.scale(_scaleX, isNumber(scaleY) ? scaleY : 1); + }, + + + /** + * Scale the image on the y-axis. + * @param {number} scaleY - The scale ratio on the y-axis. + * @returns {Object} this + */ + scaleY: function scaleY(_scaleY) { + var scaleX = this.imageData.scaleX; + + + return this.scale(isNumber(scaleX) ? scaleX : 1, _scaleY); + }, + + + /** + * Scale the image + * @param {number} scaleX - The scale ratio on the x-axis. + * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. + * @returns {Object} this + */ + scale: function scale(scaleX) { + var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX; + var imageData = this.imageData; + + var transformed = false; + + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (this.ready && !this.disabled && this.options.scalable) { + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + transformed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + transformed = true; + } + + if (transformed) { + this.renderCanvas(true, true); + } + } + + return this; + }, + + + /** + * Get the cropped area position and size data (base on the original image) + * @param {boolean} [rounded=false] - Indicate if round the data values or not. + * @returns {Object} The result cropped data. + */ + getData: function getData$$1() { + var rounded = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + x: cropBoxData.left - canvasData.left, + y: cropBoxData.top - canvasData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + + var ratio = imageData.width / imageData.naturalWidth; + + each(data, function (n, i) { + n /= ratio; + data[i] = rounded ? Math.round(n) : n; + }); + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0 + }; + } + + if (options.rotatable) { + data.rotate = imageData.rotate || 0; + } + + if (options.scalable) { + data.scaleX = imageData.scaleX || 1; + data.scaleY = imageData.scaleY || 1; + } + + return data; + }, + + + /** + * Set the cropped area position and size with new data + * @param {Object} data - The new data. + * @returns {Object} this + */ + setData: function setData$$1(data) { + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData; + + var cropBoxData = {}; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + var transformed = false; + + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== imageData.rotate) { + imageData.rotate = data.rotate; + transformed = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) { + imageData.scaleX = data.scaleX; + transformed = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) { + imageData.scaleY = data.scaleY; + transformed = true; + } + } + + if (transformed) { + this.renderCanvas(true, true); + } + + var ratio = imageData.width / imageData.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = data.x * ratio + canvasData.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = data.y * ratio + canvasData.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + this.setCropBoxData(cropBoxData); + } + + return this; + }, + + + /** + * Get the container size data. + * @returns {Object} The result container data. + */ + getContainerData: function getContainerData() { + return this.ready ? extend({}, this.containerData) : {}; + }, + + + /** + * Get the image position and size data. + * @returns {Object} The result image data. + */ + getImageData: function getImageData() { + return this.loaded ? extend({}, this.imageData) : {}; + }, + + + /** + * Get the canvas position and size data. + * @returns {Object} The result canvas data. + */ + getCanvasData: function getCanvasData() { + var canvasData = this.canvasData; + + var data = {}; + + if (this.ready) { + each(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) { + data[n] = canvasData[n]; + }); + } + + return data; + }, + + + /** + * Set the canvas position and size with new data. + * @param {Object} data - The new canvas data. + * @returns {Object} this + */ + setCanvasData: function setCanvasData(data) { + var canvasData = this.canvasData; + var aspectRatio = canvasData.aspectRatio; + + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + canvasData.left = data.left; + } + + if (isNumber(data.top)) { + canvasData.top = data.top; + } + + if (isNumber(data.width)) { + canvasData.width = data.width; + canvasData.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvasData.height = data.height; + canvasData.width = data.height * aspectRatio; + } + + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Get the crop box position and size data. + * @returns {Object} The result crop box data. + */ + getCropBoxData: function getCropBoxData() { + var cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + left: cropBoxData.left, + top: cropBoxData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + } + + return data || {}; + }, + + + /** + * Set the crop box position and size with new data. + * @param {Object} data - The new crop box data. + * @returns {Object} this + */ + setCropBoxData: function setCropBoxData(data) { + var cropBoxData = this.cropBoxData; + var aspectRatio = this.options.aspectRatio; + + var widthChanged = void 0; + var heightChanged = void 0; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + cropBoxData.left = data.left; + } + + if (isNumber(data.top)) { + cropBoxData.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBoxData.width) { + widthChanged = true; + cropBoxData.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBoxData.height) { + heightChanged = true; + cropBoxData.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else if (heightChanged) { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.renderCropBox(); + } + + return this; + }, + + + /** + * Get a canvas drawn the cropped image. + * @param {Object} [options={}] - The config options. + * @returns {HTMLCanvasElement} - The result canvas. + */ + getCroppedCanvas: function getCroppedCanvas() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (!this.ready || !window.HTMLCanvasElement) { + return null; + } + + var canvasData = this.canvasData; + + var source = getSourceCanvas(this.image, this.imageData, canvasData, options); + + // Returns the source canvas if it is not cropped. + if (!this.cropped) { + return source; + } + + var _getData = this.getData(), + x = _getData.x, + y = _getData.y, + initialWidth = _getData.width, + initialHeight = _getData.height; + + var aspectRatio = initialWidth / initialHeight; + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.maxWidth || Infinity, + height: options.maxHeight || Infinity + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.minWidth || 0, + height: options.minHeight || 0 + }); + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.width || initialWidth, + height: options.height || initialHeight + }), + width = _getContainSizes.width, + height = _getContainSizes.height; + + width = Math.min(maxSizes.width, Math.max(minSizes.width, width)); + height = Math.min(maxSizes.height, Math.max(minSizes.height, height)); + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + + context.fillStyle = options.fillColor || 'transparent'; + context.fillRect(0, 0, width, height); + + var _options$imageSmoothi = options.imageSmoothingEnabled, + imageSmoothingEnabled = _options$imageSmoothi === undefined ? true : _options$imageSmoothi, + imageSmoothingQuality = options.imageSmoothingQuality; + + + context.imageSmoothingEnabled = imageSmoothingEnabled; + + if (imageSmoothingQuality) { + context.imageSmoothingQuality = imageSmoothingQuality; + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + var sourceWidth = source.width; + var sourceHeight = source.height; + + // Source canvas parameters + var srcX = x; + var srcY = y; + var srcWidth = void 0; + var srcHeight = void 0; + + // Destination canvas parameters + var dstX = void 0; + var dstY = void 0; + var dstWidth = void 0; + var dstHeight = void 0; + + if (srcX <= -initialWidth || srcX > sourceWidth) { + srcX = 0; + srcWidth = 0; + dstX = 0; + dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = Math.min(sourceWidth, initialWidth + srcX); + dstWidth = srcWidth; + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = Math.min(initialWidth, sourceWidth - srcX); + dstWidth = srcWidth; + } + + if (srcWidth <= 0 || srcY <= -initialHeight || srcY > sourceHeight) { + srcY = 0; + srcHeight = 0; + dstY = 0; + dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = Math.min(sourceHeight, initialHeight + srcY); + dstHeight = srcHeight; + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = Math.min(initialHeight, sourceHeight - srcY); + dstHeight = srcHeight; + } + + // All the numerical parameters should be integer for `drawImage` + // https://github.com/fengyuanchen/cropper/issues/476 + var params = [srcX, srcY, srcWidth, srcHeight]; + + // Avoid "IndexSizeError" + if (dstWidth > 0 && dstHeight > 0) { + var scale = width / initialWidth; + + params.push(dstX * scale, dstY * scale, dstWidth * scale, dstHeight * scale); + } + + context.drawImage.apply(context, [source].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + + return canvas; + }, + + + /** + * Change the aspect ratio of the crop box. + * @param {number} aspectRatio - The new aspect ratio. + * @returns {Object} this + */ + setAspectRatio: function setAspectRatio(aspectRatio) { + var options = this.options; + + + if (!this.disabled && !isUndefined(aspectRatio)) { + // 0 -> NaN + options.aspectRatio = Math.max(0, aspectRatio) || NaN; + + if (this.ready) { + this.initCropBox(); + + if (this.cropped) { + this.renderCropBox(); + } + } + } + + return this; + }, + + + /** + * Change the drag mode. + * @param {string} mode - The new drag mode. + * @returns {Object} this + */ + setDragMode: function setDragMode(mode) { + var options = this.options, + dragBox = this.dragBox, + face = this.face; + + + if (this.loaded && !this.disabled) { + var croppable = mode === DRAG_MODE_CROP; + var movable = options.movable && mode === DRAG_MODE_MOVE; + + mode = croppable || movable ? mode : DRAG_MODE_NONE; + + setData(dragBox, DATA_ACTION, mode); + toggleClass(dragBox, CLASS_CROP, croppable); + toggleClass(dragBox, CLASS_MOVE, movable); + + if (!options.cropBoxMovable) { + // Sync drag mode to crop box when it is not movable + setData(face, DATA_ACTION, mode); + toggleClass(face, CLASS_CROP, croppable); + toggleClass(face, CLASS_MOVE, movable); + } + } + + return this; + } +}; + +var AnotherCropper = WINDOW.Cropper; + +var Cropper = function () { + /** + * Create a new Cropper. + * @param {Element} element - The target element for cropping. + * @param {Object} [options={}] - The configuration options. + */ + function Cropper(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, Cropper); + + if (!element || !REGEXP_TAG_NAME.test(element.tagName)) { + throw new Error('The first argument is required and must be an or element.'); + } + + this.element = element; + this.options = extend({}, DEFAULTS, isPlainObject(options) && options); + this.complete = false; + this.cropped = false; + this.disabled = false; + this.isImg = false; + this.limited = false; + this.loaded = false; + this.ready = false; + this.replaced = false; + this.wheeling = false; + this.originalUrl = ''; + this.canvasData = null; + this.cropBoxData = null; + this.previews = null; + this.pointers = {}; + this.init(); + } + + createClass(Cropper, [{ + key: 'init', + value: function init() { + var element = this.element; + + var tagName = element.tagName.toLowerCase(); + var url = void 0; + + if (getData(element, NAMESPACE)) { + return; + } + + setData(element, NAMESPACE, this); + + if (tagName === 'img') { + this.isImg = true; + + // e.g.: "img/picture.jpg" + url = element.getAttribute('src') || ''; + this.originalUrl = url; + + // Stop when it's a blank image + if (!url) { + return; + } + + // e.g.: "http://example.com/img/picture.jpg" + url = element.src; + } else if (tagName === 'canvas' && window.HTMLCanvasElement) { + url = element.toDataURL(); + } + + this.load(url); + } + }, { + key: 'load', + value: function load(url) { + var _this = this; + + if (!url) { + return; + } + + this.url = url; + this.imageData = {}; + + var element = this.element, + options = this.options; + + + if (!options.checkOrientation || !window.ArrayBuffer) { + this.clone(); + return; + } + + // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari + if (REGEXP_DATA_URL.test(url)) { + if (REGEXP_DATA_URL_JPEG.test(url)) { + this.read(dataURLToArrayBuffer(url)); + } else { + this.clone(); + } + + return; + } + + var xhr = new XMLHttpRequest(); + + xhr.onerror = function () { + _this.clone(); + }; + + xhr.onload = function () { + _this.read(xhr.response); + }; + + if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) { + url = addTimestamp(url); + } + + xhr.open('get', url); + xhr.responseType = 'arraybuffer'; + xhr.withCredentials = element.crossOrigin === 'use-credentials'; + xhr.send(); + } + }, { + key: 'read', + value: function read(arrayBuffer) { + var options = this.options, + imageData = this.imageData; + + var orientation = getOrientation(arrayBuffer); + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + if (orientation > 1) { + this.url = arrayBufferToDataURL(arrayBuffer, 'image/jpeg'); + + var _parseOrientation = parseOrientation(orientation); + + rotate = _parseOrientation.rotate; + scaleX = _parseOrientation.scaleX; + scaleY = _parseOrientation.scaleY; + } + + if (options.rotatable) { + imageData.rotate = rotate; + } + + if (options.scalable) { + imageData.scaleX = scaleX; + imageData.scaleY = scaleY; + } + + this.clone(); + } + }, { + key: 'clone', + value: function clone() { + var element = this.element, + url = this.url; + + var crossOrigin = void 0; + var crossOriginUrl = void 0; + + if (this.options.checkCrossOrigin && isCrossOriginURL(url)) { + crossOrigin = element.crossOrigin; + + + if (crossOrigin) { + crossOriginUrl = url; + } else { + crossOrigin = 'anonymous'; + + // Bust cache when there is not a "crossOrigin" property + crossOriginUrl = addTimestamp(url); + } + } + + this.crossOrigin = crossOrigin; + this.crossOriginUrl = crossOriginUrl; + + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = crossOriginUrl || url; + + var start = proxy(this.start, this); + var stop = proxy(this.stop, this); + + this.image = image; + this.onStart = start; + this.onStop = stop; + + if (this.isImg) { + if (element.complete) { + this.start(); + } else { + addListener(element, EVENT_LOAD, start); + } + } else { + addListener(image, EVENT_LOAD, start); + addListener(image, EVENT_ERROR, stop); + addClass(image, CLASS_HIDE); + element.parentNode.insertBefore(image, element.nextSibling); + } + } + }, { + key: 'start', + value: function start(event) { + var _this2 = this; + + var image = this.isImg ? this.element : this.image; + + if (event) { + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + } + + getImageNaturalSizes(image, function (naturalWidth, naturalHeight) { + extend(_this2.imageData, { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: naturalWidth / naturalHeight + }); + _this2.loaded = true; + _this2.build(); + }); + } + }, { + key: 'stop', + value: function stop() { + var image = this.image; + + + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + image.parentNode.removeChild(image); + this.image = null; + } + }, { + key: 'build', + value: function build() { + var _this3 = this; + + if (!this.loaded) { + return; + } + + // Unbuild first when replace + if (this.ready) { + this.unbuild(); + } + + var element = this.element, + options = this.options, + image = this.image; + + // Create cropper elements + + var container = element.parentNode; + var template = document.createElement('div'); + + template.innerHTML = TEMPLATE; + + var cropper = template.querySelector('.' + NAMESPACE + '-container'); + var canvas = cropper.querySelector('.' + NAMESPACE + '-canvas'); + var dragBox = cropper.querySelector('.' + NAMESPACE + '-drag-box'); + var cropBox = cropper.querySelector('.' + NAMESPACE + '-crop-box'); + var face = cropBox.querySelector('.' + NAMESPACE + '-face'); + + this.container = container; + this.cropper = cropper; + this.canvas = canvas; + this.dragBox = dragBox; + this.cropBox = cropBox; + this.viewBox = cropper.querySelector('.' + NAMESPACE + '-view-box'); + this.face = face; + + canvas.appendChild(image); + + // Hide the original image + addClass(element, CLASS_HIDDEN); + + // Inserts the cropper after to the current image + container.insertBefore(cropper, element.nextSibling); + + // Show the image if is hidden + if (!this.isImg) { + removeClass(image, CLASS_HIDE); + } + + this.initPreview(); + this.bind(); + + options.aspectRatio = Math.max(0, options.aspectRatio) || NaN; + options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0; + + this.cropped = options.autoCrop; + + if (options.autoCrop) { + if (options.modal) { + addClass(dragBox, CLASS_MODAL); + } + } else { + addClass(cropBox, CLASS_HIDDEN); + } + + if (!options.guides) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-dashed'), CLASS_HIDDEN); + } + + if (!options.center) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-center'), CLASS_HIDDEN); + } + + if (options.background) { + addClass(cropper, NAMESPACE + '-bg'); + } + + if (!options.highlight) { + addClass(face, CLASS_INVISIBLE); + } + + if (options.cropBoxMovable) { + addClass(face, CLASS_MOVE); + setData(face, DATA_ACTION, ACTION_ALL); + } + + if (!options.cropBoxResizable) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-line'), CLASS_HIDDEN); + addClass(cropBox.getElementsByClassName(NAMESPACE + '-point'), CLASS_HIDDEN); + } + + this.setDragMode(options.dragMode); + this.render(); + this.ready = true; + this.setData(options.data); + + // Call the "ready" option asynchronously to keep "image.cropper" is defined + this.completing = setTimeout(function () { + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, { + once: true + }); + } + + dispatchEvent(element, EVENT_READY); + dispatchEvent(element, EVENT_CROP, _this3.getData()); + + _this3.complete = true; + }, 0); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.ready) { + return; + } + + if (!this.complete) { + clearTimeout(this.completing); + } + + this.ready = false; + this.complete = false; + this.initialImageData = null; + + // Clear `initialCanvasData` is necessary when replace + this.initialCanvasData = null; + this.initialCropBoxData = null; + this.containerData = null; + this.canvasData = null; + + // Clear `cropBoxData` is necessary when replace + this.cropBoxData = null; + this.unbind(); + this.resetPreview(); + this.previews = null; + this.viewBox = null; + this.cropBox = null; + this.dragBox = null; + this.canvas = null; + this.container = null; + this.cropper.parentNode.removeChild(this.cropper); + this.cropper = null; + } + + /** + * Get the no conflict cropper class. + * @returns {Cropper} The cropper class. + */ + + }], [{ + key: 'noConflict', + value: function noConflict() { + window.Cropper = AnotherCropper; + return Cropper; + } + + /** + * Change the default options. + * @param {Object} options - The new default options. + */ + + }, { + key: 'setDefaults', + value: function setDefaults(options) { + extend(DEFAULTS, isPlainObject(options) && options); + } + }]); + return Cropper; +}(); + +extend(Cropper.prototype, render, preview, events, handlers, change, methods); + +export default Cropper; diff --git a/library/cropperjs/dist/cropper.js b/library/cropperjs/dist/cropper.js new file mode 100644 index 000000000..0e837953c --- /dev/null +++ b/library/cropperjs/dist/cropper.js @@ -0,0 +1,3766 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:27:18.062Z + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Cropper = factory()); +}(this, (function () { 'use strict'; + +var WINDOW = typeof window !== 'undefined' ? window : {}; +var NAMESPACE = 'cropper'; + +// Actions +var ACTION_ALL = 'all'; +var ACTION_CROP = 'crop'; +var ACTION_MOVE = 'move'; +var ACTION_ZOOM = 'zoom'; +var ACTION_EAST = 'e'; +var ACTION_WEST = 'w'; +var ACTION_SOUTH = 's'; +var ACTION_NORTH = 'n'; +var ACTION_NORTH_EAST = 'ne'; +var ACTION_NORTH_WEST = 'nw'; +var ACTION_SOUTH_EAST = 'se'; +var ACTION_SOUTH_WEST = 'sw'; + +// Classes +var CLASS_CROP = NAMESPACE + '-crop'; +var CLASS_DISABLED = NAMESPACE + '-disabled'; +var CLASS_HIDDEN = NAMESPACE + '-hidden'; +var CLASS_HIDE = NAMESPACE + '-hide'; +var CLASS_INVISIBLE = NAMESPACE + '-invisible'; +var CLASS_MODAL = NAMESPACE + '-modal'; +var CLASS_MOVE = NAMESPACE + '-move'; + +// Data keys +var DATA_ACTION = 'action'; +var DATA_PREVIEW = 'preview'; + +// Drag modes +var DRAG_MODE_CROP = 'crop'; +var DRAG_MODE_MOVE = 'move'; +var DRAG_MODE_NONE = 'none'; + +// Events +var EVENT_CROP = 'crop'; +var EVENT_CROP_END = 'cropend'; +var EVENT_CROP_MOVE = 'cropmove'; +var EVENT_CROP_START = 'cropstart'; +var EVENT_DBLCLICK = 'dblclick'; +var EVENT_ERROR = 'error'; +var EVENT_LOAD = 'load'; +var EVENT_POINTER_DOWN = WINDOW.PointerEvent ? 'pointerdown' : 'touchstart mousedown'; +var EVENT_POINTER_MOVE = WINDOW.PointerEvent ? 'pointermove' : 'touchmove mousemove'; +var EVENT_POINTER_UP = WINDOW.PointerEvent ? 'pointerup pointercancel' : 'touchend touchcancel mouseup'; +var EVENT_READY = 'ready'; +var EVENT_RESIZE = 'resize'; +var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; +var EVENT_ZOOM = 'zoom'; + +// RegExps +var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; +var REGEXP_DATA_URL = /^data:/; +var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/; +var REGEXP_TAG_NAME = /^(img|canvas)$/i; + +var DEFAULTS = { + // Define the view mode of the cropper + viewMode: 0, // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + dragMode: DRAG_MODE_CROP, // 'crop', 'move' or 'none' + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A selector for adding extra containers to preview + preview: '', + + // Re-render the cropper when resize the window + responsive: true, + + // Restore the cropped area after resize the window + restore: true, + + // Check if the current image is a cross-origin image + checkCrossOrigin: true, + + // Check the current image's Exif Orientation information + checkOrientation: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by dragging touch + zoomOnTouch: true, + + // Enable to zoom the image by wheeling mouse + zoomOnWheel: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + toggleDragModeOnDblclick: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + ready: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null +}; + +var TEMPLATE = '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
    ' + '
    '; + +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; +}; + + + + + + + + + + + +var classCallCheck = function (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 toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +/** + * Check if the given value is not a number. + */ +var isNaN = Number.isNaN || WINDOW.isNaN; + +/** + * Check if the given value is a number. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a number, else `false`. + */ +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +/** + * Check if the given value is undefined. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is undefined, else `false`. + */ +function isUndefined(value) { + return typeof value === 'undefined'; +} + +/** + * Check if the given value is an object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is an object, else `false`. + */ +function isObject(value) { + return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null; +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Check if the given value is a plain object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a plain object, else `false`. + */ + +function isPlainObject(value) { + if (!isObject(value)) { + return false; + } + + try { + var _constructor = value.constructor; + var prototype = _constructor.prototype; + + + return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (e) { + return false; + } +} + +/** + * Check if the given value is a function. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a function, else `false`. + */ +function isFunction(value) { + return typeof value === 'function'; +} + +/** + * Iterate the given data. + * @param {*} data - The data to iterate. + * @param {Function} callback - The process function for each element. + * @returns {*} The original data. + */ +function each(data, callback) { + if (data && isFunction(callback)) { + if (Array.isArray(data) || isNumber(data.length) /* array-like */) { + var length = data.length; + + var i = void 0; + + for (i = 0; i < length; i += 1) { + if (callback.call(data, data[i], i, data) === false) { + break; + } + } + } else if (isObject(data)) { + Object.keys(data).forEach(function (key) { + callback.call(data, data[key], key, data); + }); + } + } + + return data; +} + +/** + * Extend the given object. + * @param {*} obj - The object to be extended. + * @param {*} args - The rest objects which will be merged to the first object. + * @returns {Object} The extended object. + */ +function extend(obj) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (isObject(obj) && args.length > 0) { + if (Object.assign) { + return Object.assign.apply(Object, [obj].concat(args)); + } + + args.forEach(function (arg) { + if (isObject(arg)) { + Object.keys(arg).forEach(function (key) { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; +} + +/** + * Takes a function and returns a new one that will always have a particular context. + * @param {Function} fn - The target function. + * @param {Object} context - The new context for the function. + * @returns {boolean} The new function. + */ +function proxy(fn, context) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; + } + + return function () { + for (var _len3 = arguments.length, args2 = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args2[_key3] = arguments[_key3]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +var REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/i; + +/** + * Normalize decimal number. + * Check out {@link http://0.30000000000000004.com/ } + * @param {number} value - The value to normalize. + * @param {number} [times=100000000000] - The times for normalizing. + * @returns {number} Returns the normalized number. + */ +function normalizeDecimalNumber(value) { + var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000; + + return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value; +} + +var REGEXP_SUFFIX = /^(width|height|left|top|marginLeft|marginTop)$/; + +/** + * Apply styles to the given element. + * @param {Element} element - The target element. + * @param {Object} styles - The styles for applying. + */ +function setStyle(element, styles) { + var style = element.style; + + + each(styles, function (value, property) { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); +} + +/** + * Check if the given element has a special class. + * @param {Element} element - The element to check. + * @param {string} value - The class to search. + * @returns {boolean} Returns `true` if the special class was found. + */ +function hasClass(element, value) { + return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1; +} + +/** + * Add classes to the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be added. + */ +function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + var className = element.className.trim(); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = className + ' ' + value; + } +} + +/** + * Remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be removed. + */ +function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } +} + +/** + * Add or remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be toggled. + * @param {boolean} added - Add only. + */ +function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + toggleClass(elem, value, added); + }); + return; + } + + // IE10-11 doesn't support the second parameter of `classList.toggle` + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } +} + +var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; + +/** + * Hyphenate the given value. + * @param {string} value - The value to hyphenate. + * @returns {string} The hyphenated value. + */ +function hyphenate(value) { + return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); +} + +/** + * Get data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to get. + * @returns {string} The data value. + */ +function getData(element, name) { + if (isObject(element[name])) { + return element[name]; + } else if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute('data-' + hyphenate(name)); +} + +/** + * Set data to the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to set. + * @param {string} data - The data value. + */ +function setData(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute('data-' + hyphenate(name), data); + } +} + +/** + * Remove data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to remove. + */ +function removeData(element, name) { + if (isObject(element[name])) { + try { + delete element[name]; + } catch (e) { + element[name] = null; + } + } else if (element.dataset) { + // #128 Safari not allows to delete dataset property + try { + delete element.dataset[name]; + } catch (e) { + element.dataset[name] = null; + } + } else { + element.removeAttribute('data-' + hyphenate(name)); + } +} + +var REGEXP_SPACES = /\s+/; + +/** + * Remove event listener from the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function removeListener(element, type, listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + removeListener(element, t, listener, options); + }); + return; + } + + if (element.removeEventListener) { + element.removeEventListener(type, listener, options); + } else if (element.detachEvent) { + element.detachEvent('on' + type, listener); + } +} + +/** + * Add event listener to the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function addListener(element, type, _listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(_listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + addListener(element, t, _listener, options); + }); + return; + } + + if (options.once) { + var originalListener = _listener; + + _listener = function listener() { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + removeListener(element, type, _listener, options); + return originalListener.apply(element, args); + }; + } + + if (element.addEventListener) { + element.addEventListener(type, _listener, options); + } else if (element.attachEvent) { + element.attachEvent('on' + type, _listener); + } +} + +/** + * Dispatch event on the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Object} data - The additional event data. + * @returns {boolean} Indicate if the event is default prevented or not. + */ +function dispatchEvent(element, type, data) { + if (element.dispatchEvent) { + var event = void 0; + + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (isFunction(Event) && isFunction(CustomEvent)) { + if (isUndefined(data)) { + event = new Event(type, { + bubbles: true, + cancelable: true + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } + } else if (isUndefined(data)) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent('on' + type); + } + + return true; +} + +/** + * Get the offset base on the document. + * @param {Element} element - The target element. + * @returns {Object} The offset data. + */ +function getOffset(element) { + var doc = document.documentElement; + var box = element.getBoundingClientRect(); + + return { + left: box.left + ((window.scrollX || doc && doc.scrollLeft || 0) - (doc && doc.clientLeft || 0)), + top: box.top + ((window.scrollY || doc && doc.scrollTop || 0) - (doc && doc.clientTop || 0)) + }; +} + +/** + * Empty an element. + * @param {Element} element - The element to empty. + */ +function empty(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +var location = WINDOW.location; + +var REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i; + +/** + * Check if the given URL is a cross origin URL. + * @param {string} url - The target URL. + * @returns {boolean} Returns `true` if the given URL is a cross origin URL, else `false`. + */ +function isCrossOriginURL(url) { + var parts = url.match(REGEXP_ORIGINS); + + return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port); +} + +/** + * Add timestamp to the given URL. + * @param {string} url - The target URL. + * @returns {string} The result URL. + */ +function addTimestamp(url) { + var timestamp = 'timestamp=' + new Date().getTime(); + + return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp; +} + +/** + * Get transforms base on the given object. + * @param {Object} obj - The target object. + * @returns {string} A string contains transform values. + */ +function getTransforms(_ref) { + var rotate = _ref.rotate, + scaleX = _ref.scaleX, + scaleY = _ref.scaleY, + translateX = _ref.translateX, + translateY = _ref.translateY; + + var values = []; + + if (isNumber(translateX) && translateX !== 0) { + values.push('translateX(' + translateX + 'px)'); + } + + if (isNumber(translateY) && translateY !== 0) { + values.push('translateY(' + translateY + 'px)'); + } + + // Rotate should come first before scale to match orientation transform + if (isNumber(rotate) && rotate !== 0) { + values.push('rotate(' + rotate + 'deg)'); + } + + if (isNumber(scaleX) && scaleX !== 1) { + values.push('scaleX(' + scaleX + ')'); + } + + if (isNumber(scaleY) && scaleY !== 1) { + values.push('scaleY(' + scaleY + ')'); + } + + var transform = values.length ? values.join(' ') : 'none'; + + return { + WebkitTransform: transform, + msTransform: transform, + transform: transform + }; +} + +var navigator = WINDOW.navigator; + +var IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent); + +/** + * Get an image's natural sizes. + * @param {string} image - The target image. + * @param {Function} callback - The callback function. + */ +function getImageNaturalSizes(image, callback) { + // Modern browsers (except Safari) + if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) { + callback(image.naturalWidth, image.naturalHeight); + return; + } + + var newImage = document.createElement('img'); + var body = document.body || document.documentElement; + + newImage.onload = function () { + callback(newImage.width, newImage.height); + + if (!IS_SAFARI_OR_UIWEBVIEW) { + body.removeChild(newImage); + } + }; + + newImage.src = image.src; + + // iOS Safari will convert the image automatically + // with its orientation once append it into DOM (#279) + if (!IS_SAFARI_OR_UIWEBVIEW) { + newImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;'; + body.appendChild(newImage); + } +} + +/** + * Get the max ratio of a group of pointers. + * @param {string} pointers - The target pointers. + * @returns {number} The result ratio. + */ +function getMaxZoomRatio(pointers) { + var pointers2 = extend({}, pointers); + var ratios = []; + + each(pointers, function (pointer, pointerId) { + delete pointers2[pointerId]; + + each(pointers2, function (pointer2) { + var x1 = Math.abs(pointer.startX - pointer2.startX); + var y1 = Math.abs(pointer.startY - pointer2.startY); + var x2 = Math.abs(pointer.endX - pointer2.endX); + var y2 = Math.abs(pointer.endY - pointer2.endY); + var z1 = Math.sqrt(x1 * x1 + y1 * y1); + var z2 = Math.sqrt(x2 * x2 + y2 * y2); + var ratio = (z2 - z1) / z1; + + ratios.push(ratio); + }); + }); + + ratios.sort(function (a, b) { + return Math.abs(a) < Math.abs(b); + }); + + return ratios[0]; +} + +/** + * Get a pointer from an event object. + * @param {Object} event - The target event object. + * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not. + * @returns {Object} The result pointer contains start and/or end point coordinates. + */ +function getPointer(_ref2, endOnly) { + var pageX = _ref2.pageX, + pageY = _ref2.pageY; + + var end = { + endX: pageX, + endY: pageY + }; + + if (endOnly) { + return end; + } + + return extend({ + startX: pageX, + startY: pageY + }, end); +} + +/** + * Get the center point coordinate of a group of pointers. + * @param {Object} pointers - The target pointers. + * @returns {Object} The center point coordinate. + */ +function getPointersCenter(pointers) { + var pageX = 0; + var pageY = 0; + var count = 0; + + each(pointers, function (_ref3) { + var startX = _ref3.startX, + startY = _ref3.startY; + + pageX += startX; + pageY += startY; + count += 1; + }); + + pageX /= count; + pageY /= count; + + return { + pageX: pageX, + pageY: pageY + }; +} + +/** + * Check if the given value is a finite number. + */ +var isFinite = Number.isFinite || WINDOW.isFinite; + +/** + * Get the max sizes in a rectangle under the given aspect ratio. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getContainSizes(_ref4) { + var aspectRatio = _ref4.aspectRatio, + height = _ref4.height, + width = _ref4.width; + + var isValidNumber = function isValidNumber(value) { + return isFinite(value) && value > 0; + }; + + if (isValidNumber(width) && isValidNumber(height)) { + if (height * aspectRatio > width) { + height = width / aspectRatio; + } else { + width = height * aspectRatio; + } + } else if (isValidNumber(width)) { + height = width / aspectRatio; + } else if (isValidNumber(height)) { + width = height * aspectRatio; + } + + return { + width: width, + height: height + }; +} + +/** + * Get the new sizes of a rectangle after rotated. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getRotatedSizes(_ref5) { + var width = _ref5.width, + height = _ref5.height, + degree = _ref5.degree; + + degree = Math.abs(degree) % 180; + + if (degree === 90) { + return { + width: height, + height: width + }; + } + + var arc = degree % 90 * Math.PI / 180; + var sinArc = Math.sin(arc); + var cosArc = Math.cos(arc); + var newWidth = width * cosArc + height * sinArc; + var newHeight = width * sinArc + height * cosArc; + + return degree > 90 ? { + width: newHeight, + height: newWidth + } : { + width: newWidth, + height: newHeight + }; +} + +/** + * Get a canvas which drew the given image. + * @param {HTMLImageElement} image - The image for drawing. + * @param {Object} imageData - The image data. + * @param {Object} canvasData - The canvas data. + * @param {Object} options - The options. + * @returns {HTMLCanvasElement} The result canvas. + */ +function getSourceCanvas(image, _ref6, _ref7, _ref8) { + var imageNaturalWidth = _ref6.naturalWidth, + imageNaturalHeight = _ref6.naturalHeight, + _ref6$rotate = _ref6.rotate, + rotate = _ref6$rotate === undefined ? 0 : _ref6$rotate, + _ref6$scaleX = _ref6.scaleX, + scaleX = _ref6$scaleX === undefined ? 1 : _ref6$scaleX, + _ref6$scaleY = _ref6.scaleY, + scaleY = _ref6$scaleY === undefined ? 1 : _ref6$scaleY; + var aspectRatio = _ref7.aspectRatio, + naturalWidth = _ref7.naturalWidth, + naturalHeight = _ref7.naturalHeight; + var _ref8$fillColor = _ref8.fillColor, + fillColor = _ref8$fillColor === undefined ? 'transparent' : _ref8$fillColor, + _ref8$imageSmoothingE = _ref8.imageSmoothingEnabled, + imageSmoothingEnabled = _ref8$imageSmoothingE === undefined ? true : _ref8$imageSmoothingE, + _ref8$imageSmoothingQ = _ref8.imageSmoothingQuality, + imageSmoothingQuality = _ref8$imageSmoothingQ === undefined ? 'low' : _ref8$imageSmoothingQ, + _ref8$maxWidth = _ref8.maxWidth, + maxWidth = _ref8$maxWidth === undefined ? Infinity : _ref8$maxWidth, + _ref8$maxHeight = _ref8.maxHeight, + maxHeight = _ref8$maxHeight === undefined ? Infinity : _ref8$maxHeight, + _ref8$minWidth = _ref8.minWidth, + minWidth = _ref8$minWidth === undefined ? 0 : _ref8$minWidth, + _ref8$minHeight = _ref8.minHeight, + minHeight = _ref8$minHeight === undefined ? 0 : _ref8$minHeight; + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: maxWidth, + height: maxHeight + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minWidth, + height: minHeight + }); + var width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth)); + var height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight)); + var params = [-imageNaturalWidth / 2, -imageNaturalHeight / 2, imageNaturalWidth, imageNaturalHeight]; + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + context.fillStyle = fillColor; + context.fillRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + context.rotate(rotate * Math.PI / 180); + context.scale(scaleX, scaleY); + context.imageSmoothingEnabled = imageSmoothingEnabled; + context.imageSmoothingQuality = imageSmoothingQuality; + context.drawImage.apply(context, [image].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + context.restore(); + return canvas; +} + +var fromCharCode = String.fromCharCode; + +/** + * Get string from char code in data view. + * @param {DataView} dataView - The data view for read. + * @param {number} start - The start index. + * @param {number} length - The read length. + * @returns {string} The read result. + */ + +function getStringFromCharCode(dataView, start, length) { + var str = ''; + var i = void 0; + + length += start; + + for (i = start; i < length; i += 1) { + str += fromCharCode(dataView.getUint8(i)); + } + + return str; +} + +var REGEXP_DATA_URL_HEAD = /^data:.*,/; + +/** + * Transform Data URL to array buffer. + * @param {string} dataURL - The Data URL to transform. + * @returns {ArrayBuffer} The result array buffer. + */ +function dataURLToArrayBuffer(dataURL) { + var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); + var binary = atob(base64); + var arrayBuffer = new ArrayBuffer(binary.length); + var uint8 = new Uint8Array(arrayBuffer); + + each(uint8, function (value, i) { + uint8[i] = binary.charCodeAt(i); + }); + + return arrayBuffer; +} + +/** + * Transform array buffer to Data URL. + * @param {ArrayBuffer} arrayBuffer - The array buffer to transform. + * @param {string} mimeType - The mime type of the Data URL. + * @returns {string} The result Data URL. + */ +function arrayBufferToDataURL(arrayBuffer, mimeType) { + var uint8 = new Uint8Array(arrayBuffer); + var data = ''; + + // TypedArray.prototype.forEach is not supported in some browsers. + each(uint8, function (value) { + data += fromCharCode(value); + }); + + return 'data:' + mimeType + ';base64,' + btoa(data); +} + +/** + * Get orientation value from given array buffer. + * @param {ArrayBuffer} arrayBuffer - The array buffer to read. + * @returns {number} The read orientation value. + */ +function getOrientation(arrayBuffer) { + var dataView = new DataView(arrayBuffer); + var orientation = void 0; + var littleEndian = void 0; + var app1Start = void 0; + var ifdStart = void 0; + + // Only handle JPEG image (start by 0xFFD8) + if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { + var length = dataView.byteLength; + var offset = 2; + + while (offset < length) { + if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { + app1Start = offset; + break; + } + + offset += 1; + } + } + + if (app1Start) { + var exifIDCode = app1Start + 4; + var tiffOffset = app1Start + 10; + + if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { + var endianness = dataView.getUint16(tiffOffset); + + littleEndian = endianness === 0x4949; + + if (littleEndian || endianness === 0x4D4D /* bigEndian */) { + if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { + var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); + + if (firstIFDOffset >= 0x00000008) { + ifdStart = tiffOffset + firstIFDOffset; + } + } + } + } + } + + if (ifdStart) { + var _length = dataView.getUint16(ifdStart, littleEndian); + var _offset = void 0; + var i = void 0; + + for (i = 0; i < _length; i += 1) { + _offset = ifdStart + i * 12 + 2; + + if (dataView.getUint16(_offset, littleEndian) === 0x0112 /* Orientation */) { + // 8 is the offset of the current tag's value + _offset += 8; + + // Get the original orientation value + orientation = dataView.getUint16(_offset, littleEndian); + + // Override the orientation with its default value + dataView.setUint16(_offset, 1, littleEndian); + break; + } + } + } + + return orientation; +} + +/** + * Parse Exif Orientation value. + * @param {number} orientation - The orientation to parse. + * @returns {Object} The parsed result. + */ +function parseOrientation(orientation) { + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + switch (orientation) { + // Flip horizontal + case 2: + scaleX = -1; + break; + + // Rotate left 180° + case 3: + rotate = -180; + break; + + // Flip vertical + case 4: + scaleY = -1; + break; + + // Flip vertical and rotate right 90° + case 5: + rotate = 90; + scaleY = -1; + break; + + // Rotate right 90° + case 6: + rotate = 90; + break; + + // Flip horizontal and rotate right 90° + case 7: + rotate = 90; + scaleX = -1; + break; + + // Rotate left 90° + case 8: + rotate = -90; + break; + + default: + } + + return { + rotate: rotate, + scaleX: scaleX, + scaleY: scaleY + }; +} + +var render = { + render: function render() { + this.initContainer(); + this.initCanvas(); + this.initCropBox(); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + }, + initContainer: function initContainer() { + var element = this.element, + options = this.options, + container = this.container, + cropper = this.cropper; + + + addClass(cropper, CLASS_HIDDEN); + removeClass(element, CLASS_HIDDEN); + + var containerData = { + width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200), + height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100) + }; + + this.containerData = containerData; + + setStyle(cropper, { + width: containerData.width, + height: containerData.height + }); + + addClass(element, CLASS_HIDDEN); + removeClass(cropper, CLASS_HIDDEN); + }, + + + // Canvas (image wrapper) + initCanvas: function initCanvas() { + var containerData = this.containerData, + imageData = this.imageData; + var viewMode = this.options.viewMode; + + var rotated = Math.abs(imageData.rotate) % 180 === 90; + var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth; + var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight; + var aspectRatio = naturalWidth / naturalHeight; + var canvasWidth = containerData.width; + var canvasHeight = containerData.height; + + if (containerData.height * aspectRatio > containerData.width) { + if (viewMode === 3) { + canvasWidth = containerData.height * aspectRatio; + } else { + canvasHeight = containerData.width / aspectRatio; + } + } else if (viewMode === 3) { + canvasHeight = containerData.width / aspectRatio; + } else { + canvasWidth = containerData.height * aspectRatio; + } + + var canvasData = { + aspectRatio: aspectRatio, + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + width: canvasWidth, + height: canvasHeight + }; + + canvasData.left = (containerData.width - canvasWidth) / 2; + canvasData.top = (containerData.height - canvasHeight) / 2; + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + this.canvasData = canvasData; + this.limited = viewMode === 1 || viewMode === 2; + this.limitCanvas(true, true); + this.initialImageData = extend({}, imageData); + this.initialCanvasData = extend({}, canvasData); + }, + limitCanvas: function limitCanvas(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var viewMode = options.viewMode; + var aspectRatio = canvasData.aspectRatio; + + var cropped = this.cropped && cropBoxData; + + if (sizeLimited) { + var minCanvasWidth = Number(options.minCanvasWidth) || 0; + var minCanvasHeight = Number(options.minCanvasHeight) || 0; + + if (viewMode > 1) { + minCanvasWidth = Math.max(minCanvasWidth, containerData.width); + minCanvasHeight = Math.max(minCanvasHeight, containerData.height); + + if (viewMode === 3) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } else if (viewMode > 0) { + if (minCanvasWidth) { + minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0); + } else if (minCanvasHeight) { + minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0); + } else if (cropped) { + minCanvasWidth = cropBoxData.width; + minCanvasHeight = cropBoxData.height; + + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minCanvasWidth, + height: minCanvasHeight + }); + + minCanvasWidth = _getContainSizes.width; + minCanvasHeight = _getContainSizes.height; + + + canvasData.minWidth = minCanvasWidth; + canvasData.minHeight = minCanvasHeight; + canvasData.maxWidth = Infinity; + canvasData.maxHeight = Infinity; + } + + if (positionLimited) { + if (viewMode) { + var newCanvasLeft = containerData.width - canvasData.width; + var newCanvasTop = containerData.height - canvasData.height; + + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + canvasData.maxTop = Math.max(0, newCanvasTop); + + if (cropped && this.limited) { + canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width)); + canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height)); + canvasData.maxLeft = cropBoxData.left; + canvasData.maxTop = cropBoxData.top; + + if (viewMode === 2) { + if (canvasData.width >= containerData.width) { + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + } + + if (canvasData.height >= containerData.height) { + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxTop = Math.max(0, newCanvasTop); + } + } + } + } else { + canvasData.minLeft = -canvasData.width; + canvasData.minTop = -canvasData.height; + canvasData.maxLeft = containerData.width; + canvasData.maxTop = containerData.height; + } + } + }, + renderCanvas: function renderCanvas(changed, transformed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + + if (transformed) { + var _getRotatedSizes = getRotatedSizes({ + width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1), + height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1), + degree: imageData.rotate || 0 + }), + naturalWidth = _getRotatedSizes.width, + naturalHeight = _getRotatedSizes.height; + + var width = canvasData.width * (naturalWidth / canvasData.naturalWidth); + var height = canvasData.height * (naturalHeight / canvasData.naturalHeight); + + canvasData.left -= (width - canvasData.width) / 2; + canvasData.top -= (height - canvasData.height) / 2; + canvasData.width = width; + canvasData.height = height; + canvasData.aspectRatio = naturalWidth / naturalHeight; + canvasData.naturalWidth = naturalWidth; + canvasData.naturalHeight = naturalHeight; + this.limitCanvas(true, false); + } + + if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) { + canvasData.left = canvasData.oldLeft; + } + + if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) { + canvasData.top = canvasData.oldTop; + } + + canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth); + canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight); + + this.limitCanvas(false, true); + + canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft); + canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop); + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + setStyle(this.canvas, extend({ + width: canvasData.width, + height: canvasData.height + }, getTransforms({ + translateX: canvasData.left, + translateY: canvasData.top + }))); + + this.renderImage(changed); + + if (this.cropped && this.limited) { + this.limitCropBox(true, true); + } + }, + renderImage: function renderImage(changed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + var width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth); + var height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight); + + extend(imageData, { + width: width, + height: height, + left: (canvasData.width - width) / 2, + top: (canvasData.height - height) / 2 + }); + setStyle(this.image, extend({ + width: imageData.width, + height: imageData.height + }, getTransforms(extend({ + translateX: imageData.left, + translateY: imageData.top + }, imageData)))); + + if (changed) { + this.output(); + } + }, + initCropBox: function initCropBox() { + var options = this.options, + canvasData = this.canvasData; + var aspectRatio = options.aspectRatio; + + var autoCropArea = Number(options.autoCropArea) || 0.8; + var cropBoxData = { + width: canvasData.width, + height: canvasData.height + }; + + if (aspectRatio) { + if (canvasData.height * aspectRatio > canvasData.width) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.cropBoxData = cropBoxData; + this.limitCropBox(true, true); + + // Initialize auto crop area + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + // The width/height of auto crop area must large than "minWidth/Height" + cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea); + cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea); + cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2; + cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2; + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + this.initialCropBoxData = extend({}, cropBoxData); + }, + limitCropBox: function limitCropBox(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData, + limited = this.limited; + var aspectRatio = options.aspectRatio; + + + if (sizeLimited) { + var minCropBoxWidth = Number(options.minCropBoxWidth) || 0; + var minCropBoxHeight = Number(options.minCropBoxHeight) || 0; + var maxCropBoxWidth = Math.min(containerData.width, limited ? canvasData.width : containerData.width); + var maxCropBoxHeight = Math.min(containerData.height, limited ? canvasData.height : containerData.height); + + // The min/maxCropBoxWidth/Height must be less than container's width/height + minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width); + minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height); + + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } + } + + // The minWidth/Height must be less than maxWidth/Height + cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth); + cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight); + cropBoxData.maxWidth = maxCropBoxWidth; + cropBoxData.maxHeight = maxCropBoxHeight; + } + + if (positionLimited) { + if (limited) { + cropBoxData.minLeft = Math.max(0, canvasData.left); + cropBoxData.minTop = Math.max(0, canvasData.top); + cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width; + cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height; + } else { + cropBoxData.minLeft = 0; + cropBoxData.minTop = 0; + cropBoxData.maxLeft = containerData.width - cropBoxData.width; + cropBoxData.maxTop = containerData.height - cropBoxData.height; + } + } + }, + renderCropBox: function renderCropBox() { + var options = this.options, + containerData = this.containerData, + cropBoxData = this.cropBoxData; + + + if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) { + cropBoxData.left = cropBoxData.oldLeft; + } + + if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) { + cropBoxData.top = cropBoxData.oldTop; + } + + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + this.limitCropBox(false, true); + + cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft); + cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop); + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + if (options.movable && options.cropBoxMovable) { + // Turn to move the canvas when the crop box is equal to the container + setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width && cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL); + } + + setStyle(this.cropBox, extend({ + width: cropBoxData.width, + height: cropBoxData.height + }, getTransforms({ + translateX: cropBoxData.left, + translateY: cropBoxData.top + }))); + + if (this.cropped && this.limited) { + this.limitCanvas(true, true); + } + + if (!this.disabled) { + this.output(); + } + }, + output: function output() { + this.preview(); + + if (this.complete) { + dispatchEvent(this.element, EVENT_CROP, this.getData()); + } + } +}; + +var preview = { + initPreview: function initPreview() { + var crossOrigin = this.crossOrigin; + var preview = this.options.preview; + + var url = crossOrigin ? this.crossOriginUrl : this.url; + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = url; + this.viewBox.appendChild(image); + this.image2 = image; + + if (!preview) { + return; + } + + var previews = preview.querySelector ? [preview] : document.querySelectorAll(preview); + + this.previews = previews; + + each(previews, function (element) { + var img = document.createElement('img'); + + // Save the original size for recover + setData(element, DATA_PREVIEW, { + width: element.offsetWidth, + height: element.offsetHeight, + html: element.innerHTML + }); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * Add `height:auto` to override `height` attribute on IE8 + * (Occur only when margin-top <= -height) + */ + img.style.cssText = 'display:block;' + 'width:100%;' + 'height:auto;' + 'min-width:0!important;' + 'min-height:0!important;' + 'max-width:none!important;' + 'max-height:none!important;' + 'image-orientation:0deg!important;"'; + + empty(element); + element.appendChild(img); + }); + }, + resetPreview: function resetPreview() { + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + + setStyle(element, { + width: data.width, + height: data.height + }); + + element.innerHTML = data.html; + removeData(element, DATA_PREVIEW); + }); + }, + preview: function preview() { + var imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var cropBoxWidth = cropBoxData.width, + cropBoxHeight = cropBoxData.height; + var width = imageData.width, + height = imageData.height; + + var left = cropBoxData.left - canvasData.left - imageData.left; + var top = cropBoxData.top - canvasData.top - imageData.top; + + if (!this.cropped || this.disabled) { + return; + } + + setStyle(this.image2, extend({ + width: width, + height: height + }, getTransforms(extend({ + translateX: -left, + translateY: -top + }, imageData)))); + + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + var originalWidth = data.width; + var originalHeight = data.height; + var newWidth = originalWidth; + var newHeight = originalHeight; + var ratio = 1; + + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; + } + + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } + + setStyle(element, { + width: newWidth, + height: newHeight + }); + + setStyle(element.getElementsByTagName('img')[0], extend({ + width: width * ratio, + height: height * ratio + }, getTransforms(extend({ + translateX: -left * ratio, + translateY: -top * ratio + }, imageData)))); + }); + } +}; + +var events = { + bind: function bind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + addListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + addListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + addListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + addListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom); + } + + addListener(cropper, EVENT_POINTER_DOWN, this.onCropStart = proxy(this.cropStart, this)); + + if (options.zoomable && options.zoomOnWheel) { + addListener(cropper, EVENT_WHEEL, this.onWheel = proxy(this.wheel, this)); + } + + if (options.toggleDragModeOnDblclick) { + addListener(cropper, EVENT_DBLCLICK, this.onDblclick = proxy(this.dblclick, this)); + } + + addListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove = proxy(this.cropMove, this)); + addListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd = proxy(this.cropEnd, this)); + + if (options.responsive) { + addListener(window, EVENT_RESIZE, this.onResize = proxy(this.resize, this)); + } + }, + unbind: function unbind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + removeListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + removeListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + removeListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + removeListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + removeListener(element, EVENT_ZOOM, options.zoom); + } + + removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart); + + if (options.zoomable && options.zoomOnWheel) { + removeListener(cropper, EVENT_WHEEL, this.onWheel); + } + + if (options.toggleDragModeOnDblclick) { + removeListener(cropper, EVENT_DBLCLICK, this.onDblclick); + } + + removeListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove); + removeListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd); + + if (options.responsive) { + removeListener(window, EVENT_RESIZE, this.onResize); + } + } +}; + +var handlers = { + resize: function resize() { + var options = this.options, + container = this.container, + containerData = this.containerData; + + var minContainerWidth = Number(options.minContainerWidth) || 200; + var minContainerHeight = Number(options.minContainerHeight) || 100; + + if (this.disabled || containerData.width <= minContainerWidth || containerData.height <= minContainerHeight) { + return; + } + + var ratio = container.offsetWidth / containerData.width; + + // Resize when width changed or height changed + if (ratio !== 1 || container.offsetHeight !== containerData.height) { + var canvasData = void 0; + var cropBoxData = void 0; + + if (options.restore) { + canvasData = this.getCanvasData(); + cropBoxData = this.getCropBoxData(); + } + + this.render(); + + if (options.restore) { + this.setCanvasData(each(canvasData, function (n, i) { + canvasData[i] = n * ratio; + })); + this.setCropBoxData(each(cropBoxData, function (n, i) { + cropBoxData[i] = n * ratio; + })); + } + } + }, + dblclick: function dblclick() { + if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) { + return; + } + + this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP); + }, + wheel: function wheel(e) { + var _this = this; + + var ratio = Number(this.options.wheelZoomRatio) || 0.1; + var delta = 1; + + if (this.disabled) { + return; + } + + e.preventDefault(); + + // Limit wheel speed to prevent zoom too fast (#21) + if (this.wheeling) { + return; + } + + this.wheeling = true; + + setTimeout(function () { + _this.wheeling = false; + }, 50); + + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + this.zoom(-delta * ratio, e); + }, + cropStart: function cropStart(e) { + if (this.disabled) { + return; + } + + var options = this.options, + pointers = this.pointers; + + var action = void 0; + + if (e.changedTouches) { + // Handle touch event + each(e.changedTouches, function (touch) { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + // Handle mouse event and pointer event + pointers[e.pointerId || 0] = getPointer(e); + } + + if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { + action = ACTION_ZOOM; + } else { + action = getData(e.target, DATA_ACTION); + } + + if (!REGEXP_ACTIONS.test(action)) { + return; + } + + if (dispatchEvent(this.element, EVENT_CROP_START, { + originalEvent: e, + action: action + }) === false) { + return; + } + + e.preventDefault(); + + this.action = action; + this.cropping = false; + + if (action === ACTION_CROP) { + this.cropping = true; + addClass(this.dragBox, CLASS_MODAL); + } + }, + cropMove: function cropMove(e) { + var action = this.action; + + + if (this.disabled || !action) { + return; + } + + var pointers = this.pointers; + + + e.preventDefault(); + + if (dispatchEvent(this.element, EVENT_CROP_MOVE, { + originalEvent: e, + action: action + }) === false) { + return; + } + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + extend(pointers[touch.identifier], getPointer(touch, true)); + }); + } else { + extend(pointers[e.pointerId || 0], getPointer(e, true)); + } + + this.change(e); + }, + cropEnd: function cropEnd(e) { + if (this.disabled) { + return; + } + + var action = this.action, + pointers = this.pointers; + + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + delete pointers[touch.identifier]; + }); + } else { + delete pointers[e.pointerId || 0]; + } + + if (!action) { + return; + } + + e.preventDefault(); + + if (!Object.keys(pointers).length) { + this.action = ''; + } + + if (this.cropping) { + this.cropping = false; + toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal); + } + + dispatchEvent(this.element, EVENT_CROP_END, { + originalEvent: e, + action: action + }); + } +}; + +var change = { + change: function change(e) { + var options = this.options, + canvasData = this.canvasData, + containerData = this.containerData, + cropBoxData = this.cropBoxData, + pointers = this.pointers; + var action = this.action; + var aspectRatio = options.aspectRatio; + var left = cropBoxData.left, + top = cropBoxData.top, + width = cropBoxData.width, + height = cropBoxData.height; + + var right = left + width; + var bottom = top + height; + var minLeft = 0; + var minTop = 0; + var maxWidth = containerData.width; + var maxHeight = containerData.height; + var renderable = true; + var offset = void 0; + + // Locking aspect ratio in "free mode" by holding shift key + if (!aspectRatio && e.shiftKey) { + aspectRatio = width && height ? width / height : 1; + } + + if (this.limited) { + minLeft = cropBoxData.minLeft; + minTop = cropBoxData.minTop; + + maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width); + maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height); + } + + var pointer = pointers[Object.keys(pointers)[0]]; + var range = { + x: pointer.endX - pointer.startX, + y: pointer.endY - pointer.startY + }; + var check = function check(side) { + switch (side) { + case ACTION_EAST: + if (right + range.x > maxWidth) { + range.x = maxWidth - right; + } + + break; + + case ACTION_WEST: + if (left + range.x < minLeft) { + range.x = minLeft - left; + } + + break; + + case ACTION_NORTH: + if (top + range.y < minTop) { + range.y = minTop - top; + } + + break; + + case ACTION_SOUTH: + if (bottom + range.y > maxHeight) { + range.y = maxHeight - bottom; + } + + break; + + default: + } + }; + + switch (action) { + // Move crop box + case ACTION_ALL: + left += range.x; + top += range.y; + break; + + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_WEST; + width = 0; + } + + break; + + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_SOUTH; + height = 0; + } + + break; + + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_EAST; + width = 0; + } + + break; + + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_SOUTH); + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_NORTH; + height = 0; + } + + break; + + case ACTION_NORTH_EAST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + } + + break; + + case ACTION_NORTH_WEST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.y * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_WEST: + if (aspectRatio) { + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_EAST: + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + } + + break; + + // Move canvas + case ACTION_MOVE: + this.move(range.x, range.y); + renderable = false; + break; + + // Zoom canvas + case ACTION_ZOOM: + this.zoom(getMaxZoomRatio(pointers), e); + renderable = false; + break; + + // Create crop box + case ACTION_CROP: + if (!range.x || !range.y) { + renderable = false; + break; + } + + offset = getOffset(this.cropper); + left = pointer.startX - offset.left; + top = pointer.startY - offset.top; + width = cropBoxData.minWidth; + height = cropBoxData.minHeight; + + if (range.x > 0) { + action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; + } else if (range.x < 0) { + left -= width; + action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; + } + + if (range.y < 0) { + top -= height; + } + + // Show the crop box if is hidden + if (!this.cropped) { + removeClass(this.cropBox, CLASS_HIDDEN); + this.cropped = true; + + if (this.limited) { + this.limitCropBox(true, true); + } + } + + break; + + default: + } + + if (renderable) { + cropBoxData.width = width; + cropBoxData.height = height; + cropBoxData.left = left; + cropBoxData.top = top; + this.action = action; + this.renderCropBox(); + } + + // Override + each(pointers, function (p) { + p.startX = p.endX; + p.startY = p.endY; + }); + } +}; + +var methods = { + // Show the crop box manually + crop: function crop() { + if (this.ready && !this.disabled) { + if (!this.cropped) { + this.cropped = true; + this.limitCropBox(true, true); + + if (this.options.modal) { + addClass(this.dragBox, CLASS_MODAL); + } + + removeClass(this.cropBox, CLASS_HIDDEN); + } + + this.setCropBoxData(this.initialCropBoxData); + } + + return this; + }, + + + // Reset the image and crop box to their initial states + reset: function reset() { + if (this.ready && !this.disabled) { + this.imageData = extend({}, this.initialImageData); + this.canvasData = extend({}, this.initialCanvasData); + this.cropBoxData = extend({}, this.initialCropBoxData); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + } + + return this; + }, + + + // Clear the crop box + clear: function clear() { + if (this.cropped && !this.disabled) { + extend(this.cropBoxData, { + left: 0, + top: 0, + width: 0, + height: 0 + }); + + this.cropped = false; + this.renderCropBox(); + this.limitCanvas(true, true); + + // Render canvas after crop box rendered + this.renderCanvas(); + removeClass(this.dragBox, CLASS_MODAL); + addClass(this.cropBox, CLASS_HIDDEN); + } + + return this; + }, + + + /** + * Replace the image's src and rebuild the cropper + * @param {string} url - The new URL. + * @param {boolean} [onlyColorChanged] - Indicate if the new image only changed color. + * @returns {Object} this + */ + replace: function replace(url) { + var onlyColorChanged = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!this.disabled && url) { + if (this.isImg) { + this.element.src = url; + } + + if (onlyColorChanged) { + this.url = url; + this.image.src = url; + + if (this.ready) { + this.image2.src = url; + + each(this.previews, function (element) { + element.getElementsByTagName('img')[0].src = url; + }); + } + } else { + if (this.isImg) { + this.replaced = true; + } + + // Clear previous data + this.options.data = null; + this.load(url); + } + } + + return this; + }, + + + // Enable (unfreeze) the cropper + enable: function enable() { + if (this.ready) { + this.disabled = false; + removeClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Disable (freeze) the cropper + disable: function disable() { + if (this.ready) { + this.disabled = true; + addClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Destroy the cropper and remove the instance from the image + destroy: function destroy() { + var element = this.element, + image = this.image; + + + if (this.loaded) { + if (this.isImg && this.replaced) { + element.src = this.originalUrl; + } + + this.unbuild(); + removeClass(element, CLASS_HIDDEN); + } else if (this.isImg) { + removeListener(element, EVENT_LOAD, this.onStart); + } else if (image) { + image.parentNode.removeChild(image); + } + + removeData(element, NAMESPACE); + + return this; + }, + + + /** + * Move the canvas with relative offsets + * @param {number} offsetX - The relative offset distance on the x-axis. + * @param {number} offsetY - The relative offset distance on the y-axis. + * @returns {Object} this + */ + move: function move(offsetX, offsetY) { + var _canvasData = this.canvasData, + left = _canvasData.left, + top = _canvasData.top; + + + return this.moveTo(isUndefined(offsetX) ? offsetX : left + Number(offsetX), isUndefined(offsetY) ? offsetY : top + Number(offsetY)); + }, + + + /** + * Move the canvas to an absolute point + * @param {number} x - The x-axis coordinate. + * @param {number} [y=x] - The y-axis coordinate. + * @returns {Object} this + */ + moveTo: function moveTo(x) { + var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x; + var canvasData = this.canvasData; + + var changed = false; + + x = Number(x); + y = Number(y); + + if (this.ready && !this.disabled && this.options.movable) { + if (isNumber(x)) { + canvasData.left = x; + changed = true; + } + + if (isNumber(y)) { + canvasData.top = y; + changed = true; + } + + if (changed) { + this.renderCanvas(true); + } + } + + return this; + }, + + + /** + * Zoom the canvas with a relative ratio + * @param {number} ratio - The target ratio. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoom: function zoom(ratio, _originalEvent) { + var canvasData = this.canvasData; + + + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + return this.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, null, _originalEvent); + }, + + + /** + * Zoom the canvas to an absolute ratio + * @param {number} ratio - The target ratio. + * @param {Object} pivot - The zoom pivot point coordinate. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoomTo: function zoomTo(ratio, pivot, _originalEvent) { + var options = this.options, + canvasData = this.canvasData; + var width = canvasData.width, + height = canvasData.height, + naturalWidth = canvasData.naturalWidth, + naturalHeight = canvasData.naturalHeight; + + + ratio = Number(ratio); + + if (ratio >= 0 && this.ready && !this.disabled && options.zoomable) { + var newWidth = naturalWidth * ratio; + var newHeight = naturalHeight * ratio; + + if (dispatchEvent(this.element, EVENT_ZOOM, { + originalEvent: _originalEvent, + oldRatio: width / naturalWidth, + ratio: newWidth / naturalWidth + }) === false) { + return this; + } + + if (_originalEvent) { + var pointers = this.pointers; + + var offset = getOffset(this.cropper); + var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY + }; + + // Zoom from the triggering point of the event + canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height); + } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) { + canvasData.left -= (newWidth - width) * ((pivot.x - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((pivot.y - canvasData.top) / height); + } else { + // Zoom from the center of the canvas + canvasData.left -= (newWidth - width) / 2; + canvasData.top -= (newHeight - height) / 2; + } + + canvasData.width = newWidth; + canvasData.height = newHeight; + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Rotate the canvas with a relative degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotate: function rotate(degree) { + return this.rotateTo((this.imageData.rotate || 0) + Number(degree)); + }, + + + /** + * Rotate the canvas to an absolute degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotateTo: function rotateTo(degree) { + degree = Number(degree); + + if (isNumber(degree) && this.ready && !this.disabled && this.options.rotatable) { + this.imageData.rotate = degree % 360; + this.renderCanvas(true, true); + } + + return this; + }, + + + /** + * Scale the image on the x-axis. + * @param {number} scaleX - The scale ratio on the x-axis. + * @returns {Object} this + */ + scaleX: function scaleX(_scaleX) { + var scaleY = this.imageData.scaleY; + + + return this.scale(_scaleX, isNumber(scaleY) ? scaleY : 1); + }, + + + /** + * Scale the image on the y-axis. + * @param {number} scaleY - The scale ratio on the y-axis. + * @returns {Object} this + */ + scaleY: function scaleY(_scaleY) { + var scaleX = this.imageData.scaleX; + + + return this.scale(isNumber(scaleX) ? scaleX : 1, _scaleY); + }, + + + /** + * Scale the image + * @param {number} scaleX - The scale ratio on the x-axis. + * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. + * @returns {Object} this + */ + scale: function scale(scaleX) { + var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX; + var imageData = this.imageData; + + var transformed = false; + + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (this.ready && !this.disabled && this.options.scalable) { + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + transformed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + transformed = true; + } + + if (transformed) { + this.renderCanvas(true, true); + } + } + + return this; + }, + + + /** + * Get the cropped area position and size data (base on the original image) + * @param {boolean} [rounded=false] - Indicate if round the data values or not. + * @returns {Object} The result cropped data. + */ + getData: function getData$$1() { + var rounded = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + x: cropBoxData.left - canvasData.left, + y: cropBoxData.top - canvasData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + + var ratio = imageData.width / imageData.naturalWidth; + + each(data, function (n, i) { + n /= ratio; + data[i] = rounded ? Math.round(n) : n; + }); + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0 + }; + } + + if (options.rotatable) { + data.rotate = imageData.rotate || 0; + } + + if (options.scalable) { + data.scaleX = imageData.scaleX || 1; + data.scaleY = imageData.scaleY || 1; + } + + return data; + }, + + + /** + * Set the cropped area position and size with new data + * @param {Object} data - The new data. + * @returns {Object} this + */ + setData: function setData$$1(data) { + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData; + + var cropBoxData = {}; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + var transformed = false; + + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== imageData.rotate) { + imageData.rotate = data.rotate; + transformed = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) { + imageData.scaleX = data.scaleX; + transformed = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) { + imageData.scaleY = data.scaleY; + transformed = true; + } + } + + if (transformed) { + this.renderCanvas(true, true); + } + + var ratio = imageData.width / imageData.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = data.x * ratio + canvasData.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = data.y * ratio + canvasData.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + this.setCropBoxData(cropBoxData); + } + + return this; + }, + + + /** + * Get the container size data. + * @returns {Object} The result container data. + */ + getContainerData: function getContainerData() { + return this.ready ? extend({}, this.containerData) : {}; + }, + + + /** + * Get the image position and size data. + * @returns {Object} The result image data. + */ + getImageData: function getImageData() { + return this.loaded ? extend({}, this.imageData) : {}; + }, + + + /** + * Get the canvas position and size data. + * @returns {Object} The result canvas data. + */ + getCanvasData: function getCanvasData() { + var canvasData = this.canvasData; + + var data = {}; + + if (this.ready) { + each(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) { + data[n] = canvasData[n]; + }); + } + + return data; + }, + + + /** + * Set the canvas position and size with new data. + * @param {Object} data - The new canvas data. + * @returns {Object} this + */ + setCanvasData: function setCanvasData(data) { + var canvasData = this.canvasData; + var aspectRatio = canvasData.aspectRatio; + + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + canvasData.left = data.left; + } + + if (isNumber(data.top)) { + canvasData.top = data.top; + } + + if (isNumber(data.width)) { + canvasData.width = data.width; + canvasData.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvasData.height = data.height; + canvasData.width = data.height * aspectRatio; + } + + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Get the crop box position and size data. + * @returns {Object} The result crop box data. + */ + getCropBoxData: function getCropBoxData() { + var cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + left: cropBoxData.left, + top: cropBoxData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + } + + return data || {}; + }, + + + /** + * Set the crop box position and size with new data. + * @param {Object} data - The new crop box data. + * @returns {Object} this + */ + setCropBoxData: function setCropBoxData(data) { + var cropBoxData = this.cropBoxData; + var aspectRatio = this.options.aspectRatio; + + var widthChanged = void 0; + var heightChanged = void 0; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + cropBoxData.left = data.left; + } + + if (isNumber(data.top)) { + cropBoxData.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBoxData.width) { + widthChanged = true; + cropBoxData.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBoxData.height) { + heightChanged = true; + cropBoxData.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else if (heightChanged) { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.renderCropBox(); + } + + return this; + }, + + + /** + * Get a canvas drawn the cropped image. + * @param {Object} [options={}] - The config options. + * @returns {HTMLCanvasElement} - The result canvas. + */ + getCroppedCanvas: function getCroppedCanvas() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (!this.ready || !window.HTMLCanvasElement) { + return null; + } + + var canvasData = this.canvasData; + + var source = getSourceCanvas(this.image, this.imageData, canvasData, options); + + // Returns the source canvas if it is not cropped. + if (!this.cropped) { + return source; + } + + var _getData = this.getData(), + x = _getData.x, + y = _getData.y, + initialWidth = _getData.width, + initialHeight = _getData.height; + + var aspectRatio = initialWidth / initialHeight; + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.maxWidth || Infinity, + height: options.maxHeight || Infinity + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.minWidth || 0, + height: options.minHeight || 0 + }); + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.width || initialWidth, + height: options.height || initialHeight + }), + width = _getContainSizes.width, + height = _getContainSizes.height; + + width = Math.min(maxSizes.width, Math.max(minSizes.width, width)); + height = Math.min(maxSizes.height, Math.max(minSizes.height, height)); + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + + context.fillStyle = options.fillColor || 'transparent'; + context.fillRect(0, 0, width, height); + + var _options$imageSmoothi = options.imageSmoothingEnabled, + imageSmoothingEnabled = _options$imageSmoothi === undefined ? true : _options$imageSmoothi, + imageSmoothingQuality = options.imageSmoothingQuality; + + + context.imageSmoothingEnabled = imageSmoothingEnabled; + + if (imageSmoothingQuality) { + context.imageSmoothingQuality = imageSmoothingQuality; + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + var sourceWidth = source.width; + var sourceHeight = source.height; + + // Source canvas parameters + var srcX = x; + var srcY = y; + var srcWidth = void 0; + var srcHeight = void 0; + + // Destination canvas parameters + var dstX = void 0; + var dstY = void 0; + var dstWidth = void 0; + var dstHeight = void 0; + + if (srcX <= -initialWidth || srcX > sourceWidth) { + srcX = 0; + srcWidth = 0; + dstX = 0; + dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = Math.min(sourceWidth, initialWidth + srcX); + dstWidth = srcWidth; + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = Math.min(initialWidth, sourceWidth - srcX); + dstWidth = srcWidth; + } + + if (srcWidth <= 0 || srcY <= -initialHeight || srcY > sourceHeight) { + srcY = 0; + srcHeight = 0; + dstY = 0; + dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = Math.min(sourceHeight, initialHeight + srcY); + dstHeight = srcHeight; + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = Math.min(initialHeight, sourceHeight - srcY); + dstHeight = srcHeight; + } + + // All the numerical parameters should be integer for `drawImage` + // https://github.com/fengyuanchen/cropper/issues/476 + var params = [srcX, srcY, srcWidth, srcHeight]; + + // Avoid "IndexSizeError" + if (dstWidth > 0 && dstHeight > 0) { + var scale = width / initialWidth; + + params.push(dstX * scale, dstY * scale, dstWidth * scale, dstHeight * scale); + } + + context.drawImage.apply(context, [source].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + + return canvas; + }, + + + /** + * Change the aspect ratio of the crop box. + * @param {number} aspectRatio - The new aspect ratio. + * @returns {Object} this + */ + setAspectRatio: function setAspectRatio(aspectRatio) { + var options = this.options; + + + if (!this.disabled && !isUndefined(aspectRatio)) { + // 0 -> NaN + options.aspectRatio = Math.max(0, aspectRatio) || NaN; + + if (this.ready) { + this.initCropBox(); + + if (this.cropped) { + this.renderCropBox(); + } + } + } + + return this; + }, + + + /** + * Change the drag mode. + * @param {string} mode - The new drag mode. + * @returns {Object} this + */ + setDragMode: function setDragMode(mode) { + var options = this.options, + dragBox = this.dragBox, + face = this.face; + + + if (this.loaded && !this.disabled) { + var croppable = mode === DRAG_MODE_CROP; + var movable = options.movable && mode === DRAG_MODE_MOVE; + + mode = croppable || movable ? mode : DRAG_MODE_NONE; + + setData(dragBox, DATA_ACTION, mode); + toggleClass(dragBox, CLASS_CROP, croppable); + toggleClass(dragBox, CLASS_MOVE, movable); + + if (!options.cropBoxMovable) { + // Sync drag mode to crop box when it is not movable + setData(face, DATA_ACTION, mode); + toggleClass(face, CLASS_CROP, croppable); + toggleClass(face, CLASS_MOVE, movable); + } + } + + return this; + } +}; + +var AnotherCropper = WINDOW.Cropper; + +var Cropper = function () { + /** + * Create a new Cropper. + * @param {Element} element - The target element for cropping. + * @param {Object} [options={}] - The configuration options. + */ + function Cropper(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, Cropper); + + if (!element || !REGEXP_TAG_NAME.test(element.tagName)) { + throw new Error('The first argument is required and must be an or element.'); + } + + this.element = element; + this.options = extend({}, DEFAULTS, isPlainObject(options) && options); + this.complete = false; + this.cropped = false; + this.disabled = false; + this.isImg = false; + this.limited = false; + this.loaded = false; + this.ready = false; + this.replaced = false; + this.wheeling = false; + this.originalUrl = ''; + this.canvasData = null; + this.cropBoxData = null; + this.previews = null; + this.pointers = {}; + this.init(); + } + + createClass(Cropper, [{ + key: 'init', + value: function init() { + var element = this.element; + + var tagName = element.tagName.toLowerCase(); + var url = void 0; + + if (getData(element, NAMESPACE)) { + return; + } + + setData(element, NAMESPACE, this); + + if (tagName === 'img') { + this.isImg = true; + + // e.g.: "img/picture.jpg" + url = element.getAttribute('src') || ''; + this.originalUrl = url; + + // Stop when it's a blank image + if (!url) { + return; + } + + // e.g.: "http://example.com/img/picture.jpg" + url = element.src; + } else if (tagName === 'canvas' && window.HTMLCanvasElement) { + url = element.toDataURL(); + } + + this.load(url); + } + }, { + key: 'load', + value: function load(url) { + var _this = this; + + if (!url) { + return; + } + + this.url = url; + this.imageData = {}; + + var element = this.element, + options = this.options; + + + if (!options.checkOrientation || !window.ArrayBuffer) { + this.clone(); + return; + } + + // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari + if (REGEXP_DATA_URL.test(url)) { + if (REGEXP_DATA_URL_JPEG.test(url)) { + this.read(dataURLToArrayBuffer(url)); + } else { + this.clone(); + } + + return; + } + + var xhr = new XMLHttpRequest(); + + xhr.onerror = function () { + _this.clone(); + }; + + xhr.onload = function () { + _this.read(xhr.response); + }; + + if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) { + url = addTimestamp(url); + } + + xhr.open('get', url); + xhr.responseType = 'arraybuffer'; + xhr.withCredentials = element.crossOrigin === 'use-credentials'; + xhr.send(); + } + }, { + key: 'read', + value: function read(arrayBuffer) { + var options = this.options, + imageData = this.imageData; + + var orientation = getOrientation(arrayBuffer); + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + if (orientation > 1) { + this.url = arrayBufferToDataURL(arrayBuffer, 'image/jpeg'); + + var _parseOrientation = parseOrientation(orientation); + + rotate = _parseOrientation.rotate; + scaleX = _parseOrientation.scaleX; + scaleY = _parseOrientation.scaleY; + } + + if (options.rotatable) { + imageData.rotate = rotate; + } + + if (options.scalable) { + imageData.scaleX = scaleX; + imageData.scaleY = scaleY; + } + + this.clone(); + } + }, { + key: 'clone', + value: function clone() { + var element = this.element, + url = this.url; + + var crossOrigin = void 0; + var crossOriginUrl = void 0; + + if (this.options.checkCrossOrigin && isCrossOriginURL(url)) { + crossOrigin = element.crossOrigin; + + + if (crossOrigin) { + crossOriginUrl = url; + } else { + crossOrigin = 'anonymous'; + + // Bust cache when there is not a "crossOrigin" property + crossOriginUrl = addTimestamp(url); + } + } + + this.crossOrigin = crossOrigin; + this.crossOriginUrl = crossOriginUrl; + + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = crossOriginUrl || url; + + var start = proxy(this.start, this); + var stop = proxy(this.stop, this); + + this.image = image; + this.onStart = start; + this.onStop = stop; + + if (this.isImg) { + if (element.complete) { + this.start(); + } else { + addListener(element, EVENT_LOAD, start); + } + } else { + addListener(image, EVENT_LOAD, start); + addListener(image, EVENT_ERROR, stop); + addClass(image, CLASS_HIDE); + element.parentNode.insertBefore(image, element.nextSibling); + } + } + }, { + key: 'start', + value: function start(event) { + var _this2 = this; + + var image = this.isImg ? this.element : this.image; + + if (event) { + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + } + + getImageNaturalSizes(image, function (naturalWidth, naturalHeight) { + extend(_this2.imageData, { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: naturalWidth / naturalHeight + }); + _this2.loaded = true; + _this2.build(); + }); + } + }, { + key: 'stop', + value: function stop() { + var image = this.image; + + + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + image.parentNode.removeChild(image); + this.image = null; + } + }, { + key: 'build', + value: function build() { + var _this3 = this; + + if (!this.loaded) { + return; + } + + // Unbuild first when replace + if (this.ready) { + this.unbuild(); + } + + var element = this.element, + options = this.options, + image = this.image; + + // Create cropper elements + + var container = element.parentNode; + var template = document.createElement('div'); + + template.innerHTML = TEMPLATE; + + var cropper = template.querySelector('.' + NAMESPACE + '-container'); + var canvas = cropper.querySelector('.' + NAMESPACE + '-canvas'); + var dragBox = cropper.querySelector('.' + NAMESPACE + '-drag-box'); + var cropBox = cropper.querySelector('.' + NAMESPACE + '-crop-box'); + var face = cropBox.querySelector('.' + NAMESPACE + '-face'); + + this.container = container; + this.cropper = cropper; + this.canvas = canvas; + this.dragBox = dragBox; + this.cropBox = cropBox; + this.viewBox = cropper.querySelector('.' + NAMESPACE + '-view-box'); + this.face = face; + + canvas.appendChild(image); + + // Hide the original image + addClass(element, CLASS_HIDDEN); + + // Inserts the cropper after to the current image + container.insertBefore(cropper, element.nextSibling); + + // Show the image if is hidden + if (!this.isImg) { + removeClass(image, CLASS_HIDE); + } + + this.initPreview(); + this.bind(); + + options.aspectRatio = Math.max(0, options.aspectRatio) || NaN; + options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0; + + this.cropped = options.autoCrop; + + if (options.autoCrop) { + if (options.modal) { + addClass(dragBox, CLASS_MODAL); + } + } else { + addClass(cropBox, CLASS_HIDDEN); + } + + if (!options.guides) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-dashed'), CLASS_HIDDEN); + } + + if (!options.center) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-center'), CLASS_HIDDEN); + } + + if (options.background) { + addClass(cropper, NAMESPACE + '-bg'); + } + + if (!options.highlight) { + addClass(face, CLASS_INVISIBLE); + } + + if (options.cropBoxMovable) { + addClass(face, CLASS_MOVE); + setData(face, DATA_ACTION, ACTION_ALL); + } + + if (!options.cropBoxResizable) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-line'), CLASS_HIDDEN); + addClass(cropBox.getElementsByClassName(NAMESPACE + '-point'), CLASS_HIDDEN); + } + + this.setDragMode(options.dragMode); + this.render(); + this.ready = true; + this.setData(options.data); + + // Call the "ready" option asynchronously to keep "image.cropper" is defined + this.completing = setTimeout(function () { + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, { + once: true + }); + } + + dispatchEvent(element, EVENT_READY); + dispatchEvent(element, EVENT_CROP, _this3.getData()); + + _this3.complete = true; + }, 0); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.ready) { + return; + } + + if (!this.complete) { + clearTimeout(this.completing); + } + + this.ready = false; + this.complete = false; + this.initialImageData = null; + + // Clear `initialCanvasData` is necessary when replace + this.initialCanvasData = null; + this.initialCropBoxData = null; + this.containerData = null; + this.canvasData = null; + + // Clear `cropBoxData` is necessary when replace + this.cropBoxData = null; + this.unbind(); + this.resetPreview(); + this.previews = null; + this.viewBox = null; + this.cropBox = null; + this.dragBox = null; + this.canvas = null; + this.container = null; + this.cropper.parentNode.removeChild(this.cropper); + this.cropper = null; + } + + /** + * Get the no conflict cropper class. + * @returns {Cropper} The cropper class. + */ + + }], [{ + key: 'noConflict', + value: function noConflict() { + window.Cropper = AnotherCropper; + return Cropper; + } + + /** + * Change the default options. + * @param {Object} options - The new default options. + */ + + }, { + key: 'setDefaults', + value: function setDefaults(options) { + extend(DEFAULTS, isPlainObject(options) && options); + } + }]); + return Cropper; +}(); + +extend(Cropper.prototype, render, preview, events, handlers, change, methods); + +return Cropper; + +}))); diff --git a/library/cropperjs/dist/cropper.min.css b/library/cropperjs/dist/cropper.min.css new file mode 100644 index 000000000..89148848a --- /dev/null +++ b/library/cropperjs/dist/cropper.min.css @@ -0,0 +1,9 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:26:29.610Z + */.cropper-container{direction:ltr;font-size:0;line-height:0;position:relative;-ms-touch-action:none;touch-action:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.cropper-container img{display:block;height:100%;image-orientation:0deg;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;width:100%}.cropper-canvas,.cropper-crop-box,.cropper-drag-box,.cropper-modal,.cropper-wrap-box{bottom:0;left:0;position:absolute;right:0;top:0}.cropper-canvas,.cropper-wrap-box{overflow:hidden}.cropper-drag-box{background-color:#fff;opacity:0}.cropper-modal{background-color:#000;opacity:.5}.cropper-view-box{display:block;height:100%;outline-color:rgba(51,153,255,.75);outline:1px solid #39f;overflow:hidden;width:100%}.cropper-dashed{border:0 dashed #eee;display:block;opacity:.5;position:absolute}.cropper-dashed.dashed-h{border-bottom-width:1px;border-top-width:1px;height:33.33333%;left:0;top:33.33333%;width:100%}.cropper-dashed.dashed-v{border-left-width:1px;border-right-width:1px;height:100%;left:33.33333%;top:0;width:33.33333%}.cropper-center{display:block;height:0;left:50%;opacity:.75;position:absolute;top:50%;width:0}.cropper-center:after,.cropper-center:before{background-color:#eee;content:" ";display:block;position:absolute}.cropper-center:before{height:1px;left:-3px;top:0;width:7px}.cropper-center:after{height:7px;left:0;top:-3px;width:1px}.cropper-face,.cropper-line,.cropper-point{display:block;height:100%;opacity:.1;position:absolute;width:100%}.cropper-face{background-color:#fff;left:0;top:0}.cropper-line{background-color:#39f}.cropper-line.line-e{cursor:ew-resize;right:-3px;top:0;width:5px}.cropper-line.line-n{cursor:ns-resize;height:5px;left:0;top:-3px}.cropper-line.line-w{cursor:ew-resize;left:-3px;top:0;width:5px}.cropper-line.line-s{bottom:-3px;cursor:ns-resize;height:5px;left:0}.cropper-point{background-color:#39f;height:5px;opacity:.75;width:5px}.cropper-point.point-e{cursor:ew-resize;margin-top:-3px;right:-3px;top:50%}.cropper-point.point-n{cursor:ns-resize;left:50%;margin-left:-3px;top:-3px}.cropper-point.point-w{cursor:ew-resize;left:-3px;margin-top:-3px;top:50%}.cropper-point.point-s{bottom:-3px;cursor:s-resize;left:50%;margin-left:-3px}.cropper-point.point-ne{cursor:nesw-resize;right:-3px;top:-3px}.cropper-point.point-nw{cursor:nwse-resize;left:-3px;top:-3px}.cropper-point.point-sw{bottom:-3px;cursor:nesw-resize;left:-3px}.cropper-point.point-se{bottom:-3px;cursor:nwse-resize;height:20px;opacity:1;right:-3px;width:20px}@media (min-width:768px){.cropper-point.point-se{height:15px;width:15px}}@media (min-width:992px){.cropper-point.point-se{height:10px;width:10px}}@media (min-width:1200px){.cropper-point.point-se{height:5px;opacity:.75;width:5px}}.cropper-point.point-se:before{background-color:#39f;bottom:-50%;content:" ";display:block;height:200%;opacity:0;position:absolute;right:-50%;width:200%}.cropper-invisible{opacity:0}.cropper-bg{background-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC")}.cropper-hide{display:block;height:0;position:absolute;width:0}.cropper-hidden{display:none!important}.cropper-move{cursor:move}.cropper-crop{cursor:crosshair}.cropper-disabled .cropper-drag-box,.cropper-disabled .cropper-face,.cropper-disabled .cropper-line,.cropper-disabled .cropper-point{cursor:not-allowed} \ No newline at end of file diff --git a/library/cropperjs/dist/cropper.min.js b/library/cropperjs/dist/cropper.min.js new file mode 100644 index 000000000..e213c6c41 --- /dev/null +++ b/library/cropperjs/dist/cropper.min.js @@ -0,0 +1,10 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:27:18.062Z + */ +!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):t.Cropper=i()}(this,function(){"use strict";var t="undefined"!=typeof window?window:{},i="cropper",e=i+"-crop",a=i+"-disabled",n=i+"-hidden",o=i+"-hide",h=i+"-modal",r=i+"-move",s="action",c="preview",l="crop",d="cropend",p="cropmove",m="cropstart",u="load",g=t.PointerEvent?"pointerdown":"touchstart mousedown",f=t.PointerEvent?"pointermove":"touchmove mousemove",v=t.PointerEvent?"pointerup pointercancel":"touchend touchcancel mouseup",w="wheel mousewheel DOMMouseScroll",x=/^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/,b=/^data:/,y=/^data:image\/jpeg;base64,/,C=/^(img|canvas)$/i,M={viewMode:0,dragMode:"crop",aspectRatio:NaN,data:null,preview:"",responsive:!0,restore:!0,checkCrossOrigin:!0,checkOrientation:!0,modal:!0,guides:!0,center:!0,highlight:!0,background:!0,autoCrop:!0,autoCropArea:.8,movable:!0,rotatable:!0,scalable:!0,zoomable:!0,zoomOnTouch:!0,zoomOnWheel:!0,wheelZoomRatio:.1,cropBoxMovable:!0,cropBoxResizable:!0,toggleDragModeOnDblclick:!0,minCanvasWidth:0,minCanvasHeight:0,minCropBoxWidth:0,minCropBoxHeight:0,minContainerWidth:200,minContainerHeight:100,ready:null,cropstart:null,cropmove:null,cropend:null,crop:null,zoom:null},D="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},B=function(t,i){if(!(t instanceof i))throw new TypeError("Cannot call a class as a function")},k=function(){function t(t,i){for(var e=0;e1?i-1:0),a=1;a0){if(Object.assign)return Object.assign.apply(Object,[t].concat(e));e.forEach(function(i){H(i)&&Object.keys(i).forEach(function(e){t[e]=i[e]})})}return t}function z(t,i){for(var e=arguments.length,a=Array(e>2?e-2:0),n=2;n1&&void 0!==arguments[1]?arguments[1]:1e11;return R.test(t)?Math.round(t*i)/i:t}var I=/^(width|height|left|top|marginLeft|marginTop)$/;function U(t,i){var e=t.style;O(i,function(t,i){I.test(i)&&W(t)&&(t+="px"),e[i]=t})}function j(t,i){if(i)if(W(t.length))O(t,function(t){j(t,i)});else if(t.classList)t.classList.add(i);else{var e=t.className.trim();e?e.indexOf(i)<0&&(t.className=e+" "+i):t.className=i}}function P(t,i){i&&(W(t.length)?O(t,function(t){P(t,i)}):t.classList?t.classList.remove(i):t.className.indexOf(i)>=0&&(t.className=t.className.replace(i,"")))}function q(t,i,e){i&&(W(t.length)?O(t,function(t){q(t,i,e)}):e?j(t,i):P(t,i))}var $=/([a-z\d])([A-Z])/g;function Q(t){return t.replace($,"$1-$2").toLowerCase()}function Z(t,i){return H(t[i])?t[i]:t.dataset?t.dataset[i]:t.getAttribute("data-"+Q(i))}function F(t,i,e){H(e)?t[i]=e:t.dataset?t.dataset[i]=e:t.setAttribute("data-"+Q(i),e)}function K(t,i){if(H(t[i]))try{delete t[i]}catch(e){t[i]=null}else if(t.dataset)try{delete t.dataset[i]}catch(e){t.dataset[i]=null}else t.removeAttribute("data-"+Q(i))}var V=/\s+/;function G(t,i,e){var a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};if(X(e)){var n=i.trim().split(V);n.length>1?O(n,function(i){G(t,i,e,a)}):t.removeEventListener?t.removeEventListener(i,e,a):t.detachEvent&&t.detachEvent("on"+i,e)}}function J(t,i,e){var a=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};if(X(e)){var n=i.trim().split(V);if(n.length>1)O(n,function(i){J(t,i,e,a)});else{if(a.once){var o=e;e=function(){for(var n=arguments.length,h=Array(n),r=0;r0};return n(a)&&n(e)?e*i>a?e=a/i:a=e*i:n(a)?e=a/i:n(e)&&(a=e*i),{width:a,height:e}}var dt=String.fromCharCode;var pt=/^data:.*,/;function mt(t){var i=new DataView(t),e=void 0,a=void 0,n=void 0,o=void 0;if(255===i.getUint8(0)&&216===i.getUint8(1))for(var h=i.byteLength,r=2;r=8&&(o=s+l)}}}if(o){var d=i.getUint16(o,a),p=void 0,m=void 0;for(m=0;mt.width?3===e?r=t.height*h:s=t.width/h:3===e?s=t.width/h:r=t.height*h;var c={aspectRatio:h,naturalWidth:n,naturalHeight:o,width:r,height:s};c.left=(t.width-r)/2,c.top=(t.height-s)/2,c.oldLeft=c.left,c.oldTop=c.top,this.canvasData=c,this.limited=1===e||2===e,this.limitCanvas(!0,!0),this.initialImageData=S({},i),this.initialCanvasData=S({},c)},limitCanvas:function(t,i){var e=this.options,a=this.containerData,n=this.canvasData,o=this.cropBoxData,h=e.viewMode,r=n.aspectRatio,s=this.cropped&&o;if(t){var c=Number(e.minCanvasWidth)||0,l=Number(e.minCanvasHeight)||0;h>1?(c=Math.max(c,a.width),l=Math.max(l,a.height),3===h&&(l*r>c?c=l*r:l=c/r)):h>0&&(c?c=Math.max(c,s?o.width:0):l?l=Math.max(l,s?o.height:0):s&&(c=o.width,(l=o.height)*r>c?c=l*r:l=c/r));var d=lt({aspectRatio:r,width:c,height:l});c=d.width,l=d.height,n.minWidth=c,n.minHeight=l,n.maxWidth=1/0,n.maxHeight=1/0}if(i)if(h){var p=a.width-n.width,m=a.height-n.height;n.minLeft=Math.min(0,p),n.minTop=Math.min(0,m),n.maxLeft=Math.max(0,p),n.maxTop=Math.max(0,m),s&&this.limited&&(n.minLeft=Math.min(o.left,o.left+(o.width-n.width)),n.minTop=Math.min(o.top,o.top+(o.height-n.height)),n.maxLeft=o.left,n.maxTop=o.top,2===h&&(n.width>=a.width&&(n.minLeft=Math.min(0,p),n.maxLeft=Math.max(0,p)),n.height>=a.height&&(n.minTop=Math.min(0,m),n.maxTop=Math.max(0,m))))}else n.minLeft=-n.width,n.minTop=-n.height,n.maxLeft=a.width,n.maxTop=a.height},renderCanvas:function(t,i){var e=this.canvasData,a=this.imageData;if(i){var n=function(t){var i=t.width,e=t.height,a=t.degree;if(90==(a=Math.abs(a)%180))return{width:e,height:i};var n=a%90*Math.PI/180,o=Math.sin(n),h=Math.cos(n),r=i*h+e*o,s=i*o+e*h;return a>90?{width:s,height:r}:{width:r,height:s}}({width:a.naturalWidth*Math.abs(a.scaleX||1),height:a.naturalHeight*Math.abs(a.scaleY||1),degree:a.rotate||0}),o=n.width,h=n.height,r=e.width*(o/e.naturalWidth),s=e.height*(h/e.naturalHeight);e.left-=(r-e.width)/2,e.top-=(s-e.height)/2,e.width=r,e.height=s,e.aspectRatio=o/h,e.naturalWidth=o,e.naturalHeight=h,this.limitCanvas(!0,!1)}(e.width>e.maxWidth||e.widthe.maxHeight||e.heighti.width?n.height=n.width/e:n.width=n.height*e),this.cropBoxData=n,this.limitCropBox(!0,!0),n.width=Math.min(Math.max(n.width,n.minWidth),n.maxWidth),n.height=Math.min(Math.max(n.height,n.minHeight),n.maxHeight),n.width=Math.max(n.minWidth,n.width*a),n.height=Math.max(n.minHeight,n.height*a),n.left=i.left+(i.width-n.width)/2,n.top=i.top+(i.height-n.height)/2,n.oldLeft=n.left,n.oldTop=n.top,this.initialCropBoxData=S({},n)},limitCropBox:function(t,i){var e=this.options,a=this.containerData,n=this.canvasData,o=this.cropBoxData,h=this.limited,r=e.aspectRatio;if(t){var s=Number(e.minCropBoxWidth)||0,c=Number(e.minCropBoxHeight)||0,l=Math.min(a.width,h?n.width:a.width),d=Math.min(a.height,h?n.height:a.height);s=Math.min(s,a.width),c=Math.min(c,a.height),r&&(s&&c?c*r>s?c=s/r:s=c*r:s?c=s/r:c&&(s=c*r),d*r>l?d=l/r:l=d*r),o.minWidth=Math.min(s,l),o.minHeight=Math.min(c,d),o.maxWidth=l,o.maxHeight=d}i&&(h?(o.minLeft=Math.max(0,n.left),o.minTop=Math.max(0,n.top),o.maxLeft=Math.min(a.width,n.left+n.width)-o.width,o.maxTop=Math.min(a.height,n.top+n.height)-o.height):(o.minLeft=0,o.minTop=0,o.maxLeft=a.width-o.width,o.maxTop=a.height-o.height))},renderCropBox:function(){var t=this.options,i=this.containerData,e=this.cropBoxData;(e.width>e.maxWidth||e.widthe.maxHeight||e.height=i.width&&e.height>=i.height?"move":"all"),U(this.cropBox,S({width:e.width,height:e.height},ot({translateX:e.left,translateY:e.top}))),this.cropped&&this.limited&&this.limitCanvas(!0,!0),this.disabled||this.output()},output:function(){this.preview(),this.complete&&_(this.element,l,this.getData())}},gt={initPreview:function(){var t=this.crossOrigin,i=this.options.preview,e=t?this.crossOriginUrl:this.url,a=document.createElement("img");if(t&&(a.crossOrigin=t),a.src=e,this.viewBox.appendChild(a),this.image2=a,i){var n=i.querySelector?[i]:document.querySelectorAll(i);this.previews=n,O(n,function(i){var a=document.createElement("img");F(i,c,{width:i.offsetWidth,height:i.offsetHeight,html:i.innerHTML}),t&&(a.crossOrigin=t),a.src=e,a.style.cssText='display:block;width:100%;height:auto;min-width:0!important;min-height:0!important;max-width:none!important;max-height:none!important;image-orientation:0deg!important;"',function(t){for(;t.firstChild;)t.removeChild(t.firstChild)}(i),i.appendChild(a)})}},resetPreview:function(){O(this.previews,function(t){var i=Z(t,c);U(t,{width:i.width,height:i.height}),t.innerHTML=i.html,K(t,c)})},preview:function(){var t=this.imageData,i=this.canvasData,e=this.cropBoxData,a=e.width,n=e.height,o=t.width,h=t.height,r=e.left-i.left-t.left,s=e.top-i.top-t.top;this.cropped&&!this.disabled&&(U(this.image2,S({width:o,height:h},ot(S({translateX:-r,translateY:-s},t)))),O(this.previews,function(i){var e=Z(i,c),l=e.width,d=e.height,p=l,m=d,u=1;a&&(m=n*(u=l/a)),n&&m>d&&(p=a*(u=d/n),m=d),U(i,{width:p,height:m}),U(i.getElementsByTagName("img")[0],S({width:o*u,height:h*u},ot(S({translateX:-r*u,translateY:-s*u},t))))}))}},ft={bind:function(){var t=this.element,i=this.options,e=this.cropper;X(i.cropstart)&&J(t,m,i.cropstart),X(i.cropmove)&&J(t,p,i.cropmove),X(i.cropend)&&J(t,d,i.cropend),X(i.crop)&&J(t,l,i.crop),X(i.zoom)&&J(t,"zoom",i.zoom),J(e,g,this.onCropStart=z(this.cropStart,this)),i.zoomable&&i.zoomOnWheel&&J(e,w,this.onWheel=z(this.wheel,this)),i.toggleDragModeOnDblclick&&J(e,"dblclick",this.onDblclick=z(this.dblclick,this)),J(t.ownerDocument,f,this.onCropMove=z(this.cropMove,this)),J(t.ownerDocument,v,this.onCropEnd=z(this.cropEnd,this)),i.responsive&&J(window,"resize",this.onResize=z(this.resize,this))},unbind:function(){var t=this.element,i=this.options,e=this.cropper;X(i.cropstart)&&G(t,m,i.cropstart),X(i.cropmove)&&G(t,p,i.cropmove),X(i.cropend)&&G(t,d,i.cropend),X(i.crop)&&G(t,l,i.crop),X(i.zoom)&&G(t,"zoom",i.zoom),G(e,g,this.onCropStart),i.zoomable&&i.zoomOnWheel&&G(e,w,this.onWheel),i.toggleDragModeOnDblclick&&G(e,"dblclick",this.onDblclick),G(t.ownerDocument,f,this.onCropMove),G(t.ownerDocument,v,this.onCropEnd),i.responsive&&G(window,"resize",this.onResize)}},vt={resize:function(){var t=this.options,i=this.container,e=this.containerData,a=Number(t.minContainerWidth)||200,n=Number(t.minContainerHeight)||100;if(!(this.disabled||e.width<=a||e.height<=n)){var o=i.offsetWidth/e.width;if(1!==o||i.offsetHeight!==e.height){var h=void 0,r=void 0;t.restore&&(h=this.getCanvasData(),r=this.getCropBoxData()),this.render(),t.restore&&(this.setCanvasData(O(h,function(t,i){h[i]=t*o})),this.setCropBoxData(O(r,function(t,i){r[i]=t*o})))}}},dblclick:function(){if(!this.disabled&&"none"!==this.options.dragMode){this.setDragMode((t=this.dragBox,i=e,(t.classList?t.classList.contains(i):t.className.indexOf(i)>-1)?"move":"crop"));var t,i}},wheel:function(t){var i=this,e=Number(this.options.wheelZoomRatio)||.1,a=1;this.disabled||(t.preventDefault(),this.wheeling||(this.wheeling=!0,setTimeout(function(){i.wheeling=!1},50),t.deltaY?a=t.deltaY>0?1:-1:t.wheelDelta?a=-t.wheelDelta/120:t.detail&&(a=t.detail>0?1:-1),this.zoom(-a*e,t)))},cropStart:function(t){if(!this.disabled){var i=this.options,e=this.pointers,a=void 0;t.changedTouches?O(t.changedTouches,function(t){e[t.identifier]=st(t)}):e[t.pointerId||0]=st(t),a=Object.keys(e).length>1&&i.zoomable&&i.zoomOnTouch?"zoom":Z(t.target,s),x.test(a)&&!1!==_(this.element,m,{originalEvent:t,action:a})&&(t.preventDefault(),this.action=a,this.cropping=!1,"crop"===a&&(this.cropping=!0,j(this.dragBox,h)))}},cropMove:function(t){var i=this.action;if(!this.disabled&&i){var e=this.pointers;t.preventDefault(),!1!==_(this.element,p,{originalEvent:t,action:i})&&(t.changedTouches?O(t.changedTouches,function(t){S(e[t.identifier],st(t,!0))}):S(e[t.pointerId||0],st(t,!0)),this.change(t))}},cropEnd:function(t){if(!this.disabled){var i=this.action,e=this.pointers;t.changedTouches?O(t.changedTouches,function(t){delete e[t.identifier]}):delete e[t.pointerId||0],i&&(t.preventDefault(),Object.keys(e).length||(this.action=""),this.cropping&&(this.cropping=!1,q(this.dragBox,h,this.cropped&&this.options.modal)),_(this.element,d,{originalEvent:t,action:i}))}}},wt={change:function(t){var i=this.options,e=this.canvasData,a=this.containerData,o=this.cropBoxData,h=this.pointers,r=this.action,s=i.aspectRatio,c=o.left,l=o.top,d=o.width,p=o.height,m=c+d,u=l+p,g=0,f=0,v=a.width,w=a.height,x=!0,b=void 0;!s&&t.shiftKey&&(s=d&&p?d/p:1),this.limited&&(g=o.minLeft,f=o.minTop,v=g+Math.min(a.width,e.width,e.left+e.width),w=f+Math.min(a.height,e.height,e.top+e.height));var y=h[Object.keys(h)[0]],C={x:y.endX-y.startX,y:y.endY-y.startY},M=function(t){switch(t){case"e":m+C.x>v&&(C.x=v-m);break;case"w":c+C.xw&&(C.y=w-u)}};switch(r){case"all":c+=C.x,l+=C.y;break;case"e":if(C.x>=0&&(m>=v||s&&(l<=f||u>=w))){x=!1;break}M("e"),d+=C.x,s&&(p=d/s,l-=C.x/s/2),d<0&&(r="w",d=0);break;case"n":if(C.y<=0&&(l<=f||s&&(c<=g||m>=v))){x=!1;break}M("n"),p-=C.y,l+=C.y,s&&(d=p*s,c+=C.y*s/2),p<0&&(r="s",p=0);break;case"w":if(C.x<=0&&(c<=g||s&&(l<=f||u>=w))){x=!1;break}M("w"),d-=C.x,c+=C.x,s&&(p=d/s,l+=C.x/s/2),d<0&&(r="e",d=0);break;case"s":if(C.y>=0&&(u>=w||s&&(c<=g||m>=v))){x=!1;break}M("s"),p+=C.y,s&&(d=p*s,c-=C.y*s/2),p<0&&(r="n",p=0);break;case"ne":if(s){if(C.y<=0&&(l<=f||m>=v)){x=!1;break}M("n"),p-=C.y,l+=C.y,d=p*s}else M("n"),M("e"),C.x>=0?mf&&(p-=C.y,l+=C.y):(p-=C.y,l+=C.y);d<0&&p<0?(r="sw",p=0,d=0):d<0?(r="nw",d=0):p<0&&(r="se",p=0);break;case"nw":if(s){if(C.y<=0&&(l<=f||c<=g)){x=!1;break}M("n"),p-=C.y,l+=C.y,d=p*s,c+=C.y*s}else M("n"),M("w"),C.x<=0?c>g?(d-=C.x,c+=C.x):C.y<=0&&l<=f&&(x=!1):(d-=C.x,c+=C.x),C.y<=0?l>f&&(p-=C.y,l+=C.y):(p-=C.y,l+=C.y);d<0&&p<0?(r="se",p=0,d=0):d<0?(r="ne",d=0):p<0&&(r="sw",p=0);break;case"sw":if(s){if(C.x<=0&&(c<=g||u>=w)){x=!1;break}M("w"),d-=C.x,c+=C.x,p=d/s}else M("s"),M("w"),C.x<=0?c>g?(d-=C.x,c+=C.x):C.y>=0&&u>=w&&(x=!1):(d-=C.x,c+=C.x),C.y>=0?u=0&&(m>=v||u>=w)){x=!1;break}M("e"),p=(d+=C.x)/s}else M("s"),M("e"),C.x>=0?m=0&&u>=w&&(x=!1):d+=C.x,C.y>=0?u0?r=C.y>0?"se":"ne":C.x<0&&(c-=d,r=C.y>0?"sw":"nw"),C.y<0&&(l-=p),this.cropped||(P(this.cropBox,n),this.cropped=!0,this.limited&&this.limitCropBox(!0,!0))}x&&(o.width=d,o.height=p,o.left=c,o.top=l,this.action=r,this.renderCropBox()),O(h,function(t){t.startX=t.endX,t.startY=t.endY})}},xt={crop:function(){return this.ready&&!this.disabled&&(this.cropped||(this.cropped=!0,this.limitCropBox(!0,!0),this.options.modal&&j(this.dragBox,h),P(this.cropBox,n)),this.setCropBoxData(this.initialCropBoxData)),this},reset:function(){return this.ready&&!this.disabled&&(this.imageData=S({},this.initialImageData),this.canvasData=S({},this.initialCanvasData),this.cropBoxData=S({},this.initialCropBoxData),this.renderCanvas(),this.cropped&&this.renderCropBox()),this},clear:function(){return this.cropped&&!this.disabled&&(S(this.cropBoxData,{left:0,top:0,width:0,height:0}),this.cropped=!1,this.renderCropBox(),this.limitCanvas(!0,!0),this.renderCanvas(),P(this.dragBox,h),j(this.cropBox,n)),this},replace:function(t){var i=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return!this.disabled&&t&&(this.isImg&&(this.element.src=t),i?(this.url=t,this.image.src=t,this.ready&&(this.image2.src=t,O(this.previews,function(i){i.getElementsByTagName("img")[0].src=t}))):(this.isImg&&(this.replaced=!0),this.options.data=null,this.load(t))),this},enable:function(){return this.ready&&(this.disabled=!1,P(this.cropper,a)),this},disable:function(){return this.ready&&(this.disabled=!0,j(this.cropper,a)),this},destroy:function(){var t=this.element,e=this.image;return this.loaded?(this.isImg&&this.replaced&&(t.src=this.originalUrl),this.unbuild(),P(t,n)):this.isImg?G(t,u,this.onStart):e&&e.parentNode.removeChild(e),K(t,i),this},move:function(t,i){var e=this.canvasData,a=e.left,n=e.top;return this.moveTo(N(t)?t:a+Number(t),N(i)?i:n+Number(i))},moveTo:function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:t,e=this.canvasData,a=!1;return t=Number(t),i=Number(i),this.ready&&!this.disabled&&this.options.movable&&(W(t)&&(e.left=t,a=!0),W(i)&&(e.top=i,a=!0),a&&this.renderCanvas(!0)),this},zoom:function(t,i){var e=this.canvasData;return t=(t=Number(t))<0?1/(1-t):1+t,this.zoomTo(e.width*t/e.naturalWidth,null,i)},zoomTo:function(t,i,e){var a=this.options,n=this.canvasData,o=n.width,h=n.height,r=n.naturalWidth,s=n.naturalHeight;if((t=Number(t))>=0&&this.ready&&!this.disabled&&a.zoomable){var c=r*t,l=s*t;if(!1===_(this.element,"zoom",{originalEvent:e,oldRatio:o/r,ratio:c/r}))return this;if(e){var d=this.pointers,p=tt(this.cropper),m=d&&Object.keys(d).length?function(t){var i=0,e=0,a=0;return O(t,function(t){var n=t.startX,o=t.startY;i+=n,e+=o,a+=1}),{pageX:i/=a,pageY:e/=a}}(d):{pageX:e.pageX,pageY:e.pageY};n.left-=(c-o)*((m.pageX-p.left-n.left)/o),n.top-=(l-h)*((m.pageY-p.top-n.top)/h)}else Y(i)&&W(i.x)&&W(i.y)?(n.left-=(c-o)*((i.x-n.left)/o),n.top-=(l-h)*((i.y-n.top)/h)):(n.left-=(c-o)/2,n.top-=(l-h)/2);n.width=c,n.height=l,this.renderCanvas(!0)}return this},rotate:function(t){return this.rotateTo((this.imageData.rotate||0)+Number(t))},rotateTo:function(t){return W(t=Number(t))&&this.ready&&!this.disabled&&this.options.rotatable&&(this.imageData.rotate=t%360,this.renderCanvas(!0,!0)),this},scaleX:function(t){var i=this.imageData.scaleY;return this.scale(t,W(i)?i:1)},scaleY:function(t){var i=this.imageData.scaleX;return this.scale(W(i)?i:1,t)},scale:function(t){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:t,e=this.imageData,a=!1;return t=Number(t),i=Number(i),this.ready&&!this.disabled&&this.options.scalable&&(W(t)&&(e.scaleX=t,a=!0),W(i)&&(e.scaleY=i,a=!0),a&&this.renderCanvas(!0,!0)),this},getData:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0],i=this.options,e=this.imageData,a=this.canvasData,n=this.cropBoxData,o=void 0;if(this.ready&&this.cropped){o={x:n.left-a.left,y:n.top-a.top,width:n.width,height:n.height};var h=e.width/e.naturalWidth;O(o,function(i,e){i/=h,o[e]=t?Math.round(i):i})}else o={x:0,y:0,width:0,height:0};return i.rotatable&&(o.rotate=e.rotate||0),i.scalable&&(o.scaleX=e.scaleX||1,o.scaleY=e.scaleY||1),o},setData:function(t){var i=this.options,e=this.imageData,a=this.canvasData,n={};if(X(t)&&(t=t.call(this.element)),this.ready&&!this.disabled&&Y(t)){var o=!1;i.rotatable&&W(t.rotate)&&t.rotate!==e.rotate&&(e.rotate=t.rotate,o=!0),i.scalable&&(W(t.scaleX)&&t.scaleX!==e.scaleX&&(e.scaleX=t.scaleX,o=!0),W(t.scaleY)&&t.scaleY!==e.scaleY&&(e.scaleY=t.scaleY,o=!0)),o&&this.renderCanvas(!0,!0);var h=e.width/e.naturalWidth;W(t.x)&&(n.left=t.x*h+a.left),W(t.y)&&(n.top=t.y*h+a.top),W(t.width)&&(n.width=t.width*h),W(t.height)&&(n.height=t.height*h),this.setCropBoxData(n)}return this},getContainerData:function(){return this.ready?S({},this.containerData):{}},getImageData:function(){return this.loaded?S({},this.imageData):{}},getCanvasData:function(){var t=this.canvasData,i={};return this.ready&&O(["left","top","width","height","naturalWidth","naturalHeight"],function(e){i[e]=t[e]}),i},setCanvasData:function(t){var i=this.canvasData,e=i.aspectRatio;return X(t)&&(t=t.call(this.element)),this.ready&&!this.disabled&&Y(t)&&(W(t.left)&&(i.left=t.left),W(t.top)&&(i.top=t.top),W(t.width)?(i.width=t.width,i.height=t.width/e):W(t.height)&&(i.height=t.height,i.width=t.height*e),this.renderCanvas(!0)),this},getCropBoxData:function(){var t=this.cropBoxData,i=void 0;return this.ready&&this.cropped&&(i={left:t.left,top:t.top,width:t.width,height:t.height}),i||{}},setCropBoxData:function(t){var i=this.cropBoxData,e=this.options.aspectRatio,a=void 0,n=void 0;return X(t)&&(t=t.call(this.element)),this.ready&&this.cropped&&!this.disabled&&Y(t)&&(W(t.left)&&(i.left=t.left),W(t.top)&&(i.top=t.top),W(t.width)&&t.width!==i.width&&(a=!0,i.width=t.width),W(t.height)&&t.height!==i.height&&(n=!0,i.height=t.height),e&&(a?i.height=i.width/e:n&&(i.width=i.height*e)),this.renderCropBox()),this},getCroppedCanvas:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!this.ready||!window.HTMLCanvasElement)return null;var i=this.canvasData,e=function(t,i,e,a){var n=i.naturalWidth,o=i.naturalHeight,h=i.rotate,r=void 0===h?0:h,s=i.scaleX,c=void 0===s?1:s,l=i.scaleY,d=void 0===l?1:l,p=e.aspectRatio,m=e.naturalWidth,u=e.naturalHeight,g=a.fillColor,f=void 0===g?"transparent":g,v=a.imageSmoothingEnabled,w=void 0===v||v,x=a.imageSmoothingQuality,b=void 0===x?"low":x,y=a.maxWidth,C=void 0===y?1/0:y,M=a.maxHeight,D=void 0===M?1/0:M,B=a.minWidth,k=void 0===B?0:B,T=a.minHeight,W=void 0===T?0:T,N=document.createElement("canvas"),H=N.getContext("2d"),L=lt({aspectRatio:p,width:C,height:D}),Y=lt({aspectRatio:p,width:k,height:W}),X=Math.min(L.width,Math.max(Y.width,m)),O=Math.min(L.height,Math.max(Y.height,u)),S=[-n/2,-o/2,n,o];return N.width=A(X),N.height=A(O),H.fillStyle=f,H.fillRect(0,0,X,O),H.save(),H.translate(X/2,O/2),H.rotate(r*Math.PI/180),H.scale(c,d),H.imageSmoothingEnabled=w,H.imageSmoothingQuality=b,H.drawImage.apply(H,[t].concat(E(S.map(function(t){return Math.floor(A(t))})))),H.restore(),N}(this.image,this.imageData,i,t);if(!this.cropped)return e;var a=this.getData(),n=a.x,o=a.y,h=a.width,r=a.height,s=h/r,c=lt({aspectRatio:s,width:t.maxWidth||1/0,height:t.maxHeight||1/0}),l=lt({aspectRatio:s,width:t.minWidth||0,height:t.minHeight||0}),d=lt({aspectRatio:s,width:t.width||h,height:t.height||r}),p=d.width,m=d.height;p=Math.min(c.width,Math.max(l.width,p)),m=Math.min(c.height,Math.max(l.height,m));var u=document.createElement("canvas"),g=u.getContext("2d");u.width=A(p),u.height=A(m),g.fillStyle=t.fillColor||"transparent",g.fillRect(0,0,p,m);var f=t.imageSmoothingEnabled,v=void 0===f||f,w=t.imageSmoothingQuality;g.imageSmoothingEnabled=v,w&&(g.imageSmoothingQuality=w);var x=e.width,b=e.height,y=n,C=o,M=void 0,D=void 0,B=void 0,k=void 0,T=void 0,W=void 0;y<=-h||y>x?(y=0,M=0,B=0,T=0):y<=0?(B=-y,y=0,T=M=Math.min(x,h+y)):y<=x&&(B=0,T=M=Math.min(h,x-y)),M<=0||C<=-r||C>b?(C=0,D=0,k=0,W=0):C<=0?(k=-C,C=0,W=D=Math.min(b,r+C)):C<=b&&(k=0,W=D=Math.min(r,b-C));var N=[y,C,M,D];if(T>0&&W>0){var H=p/h;N.push(B*H,k*H,T*H,W*H)}return g.drawImage.apply(g,[e].concat(E(N.map(function(t){return Math.floor(A(t))})))),u},setAspectRatio:function(t){var i=this.options;return this.disabled||N(t)||(i.aspectRatio=Math.max(0,t)||NaN,this.ready&&(this.initCropBox(),this.cropped&&this.renderCropBox())),this},setDragMode:function(t){var i=this.options,a=this.dragBox,n=this.face;if(this.loaded&&!this.disabled){var o="crop"===t,h=i.movable&&"move"===t;F(a,s,t=o||h?t:"none"),q(a,e,o),q(a,r,h),i.cropBoxMovable||(F(n,s,t),q(n,e,o),q(n,r,h))}return this}},bt=t.Cropper,yt=function(){function t(i){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(B(this,t),!i||!C.test(i.tagName))throw new Error("The first argument is required and must be an or element.");this.element=i,this.options=S({},M,Y(e)&&e),this.complete=!1,this.cropped=!1,this.disabled=!1,this.isImg=!1,this.limited=!1,this.loaded=!1,this.ready=!1,this.replaced=!1,this.wheeling=!1,this.originalUrl="",this.canvasData=null,this.cropBoxData=null,this.previews=null,this.pointers={},this.init()}return k(t,[{key:"init",value:function(){var t=this.element,e=t.tagName.toLowerCase(),a=void 0;if(!Z(t,i)){if(F(t,i,this),"img"===e){if(this.isImg=!0,a=t.getAttribute("src")||"",this.originalUrl=a,!a)return;a=t.src}else"canvas"===e&&window.HTMLCanvasElement&&(a=t.toDataURL());this.load(a)}}},{key:"load",value:function(t){var i=this;if(t){this.url=t,this.imageData={};var e=this.element,a=this.options;if(a.checkOrientation&&window.ArrayBuffer)if(b.test(t))y.test(t)?this.read(function(t){var i=t.replace(pt,""),e=atob(i),a=new ArrayBuffer(e.length),n=new Uint8Array(a);return O(n,function(t,i){n[i]=e.charCodeAt(i)}),a}(t)):this.clone();else{var n=new XMLHttpRequest;n.onerror=function(){i.clone()},n.onload=function(){i.read(n.response)},a.checkCrossOrigin&&at(t)&&e.crossOrigin&&(t=nt(t)),n.open("get",t),n.responseType="arraybuffer",n.withCredentials="use-credentials"===e.crossOrigin,n.send()}else this.clone()}}},{key:"read",value:function(t){var i=this.options,e=this.imageData,a=mt(t),n=0,o=1,h=1;if(a>1){this.url=function(t,i){var e="";return O(new Uint8Array(t),function(t){e+=dt(t)}),"data:"+i+";base64,"+btoa(e)}(t,"image/jpeg");var r=function(t){var i=0,e=1,a=1;switch(t){case 2:e=-1;break;case 3:i=-180;break;case 4:a=-1;break;case 5:i=90,a=-1;break;case 6:i=90;break;case 7:i=90,e=-1;break;case 8:i=-90}return{rotate:i,scaleX:e,scaleY:a}}(a);n=r.rotate,o=r.scaleX,h=r.scaleY}i.rotatable&&(e.rotate=n),i.scalable&&(e.scaleX=o,e.scaleY=h),this.clone()}},{key:"clone",value:function(){var t=this.element,i=this.url,e=void 0,a=void 0;this.options.checkCrossOrigin&&at(i)&&((e=t.crossOrigin)?a=i:(e="anonymous",a=nt(i))),this.crossOrigin=e,this.crossOriginUrl=a;var n=document.createElement("img");e&&(n.crossOrigin=e),n.src=a||i;var h=z(this.start,this),r=z(this.stop,this);this.image=n,this.onStart=h,this.onStop=r,this.isImg?t.complete?this.start():J(t,u,h):(J(n,u,h),J(n,"error",r),j(n,o),t.parentNode.insertBefore(n,t.nextSibling))}},{key:"start",value:function(t){var i=this,e=this.isImg?this.element:this.image;t&&(G(e,u,this.onStart),G(e,"error",this.onStop)),function(t,i){if(!t.naturalWidth||rt){var e=document.createElement("img"),a=document.body||document.documentElement;e.onload=function(){i(e.width,e.height),rt||a.removeChild(e)},e.src=t.src,rt||(e.style.cssText="left:0;max-height:none!important;max-width:none!important;min-height:0!important;min-width:0!important;opacity:0;position:absolute;top:0;z-index:-1;",a.appendChild(e))}else i(t.naturalWidth,t.naturalHeight)}(e,function(t,e){S(i.imageData,{naturalWidth:t,naturalHeight:e,aspectRatio:t/e}),i.loaded=!0,i.build()})}},{key:"stop",value:function(){var t=this.image;G(t,u,this.onStart),G(t,"error",this.onStop),t.parentNode.removeChild(t),this.image=null}},{key:"build",value:function(){var t=this;if(this.loaded){this.ready&&this.unbuild();var e=this.element,a=this.options,c=this.image,d=e.parentNode,p=document.createElement("div");p.innerHTML='
    ';var m=p.querySelector("."+i+"-container"),u=m.querySelector("."+i+"-canvas"),g=m.querySelector("."+i+"-drag-box"),f=m.querySelector("."+i+"-crop-box"),v=f.querySelector("."+i+"-face");this.container=d,this.cropper=m,this.canvas=u,this.dragBox=g,this.cropBox=f,this.viewBox=m.querySelector("."+i+"-view-box"),this.face=v,u.appendChild(c),j(e,n),d.insertBefore(m,e.nextSibling),this.isImg||P(c,o),this.initPreview(),this.bind(),a.aspectRatio=Math.max(0,a.aspectRatio)||NaN,a.viewMode=Math.max(0,Math.min(3,Math.round(a.viewMode)))||0,this.cropped=a.autoCrop,a.autoCrop?a.modal&&j(g,h):j(f,n),a.guides||j(f.getElementsByClassName(i+"-dashed"),n),a.center||j(f.getElementsByClassName(i+"-center"),n),a.background&&j(m,i+"-bg"),a.highlight||j(v,"cropper-invisible"),a.cropBoxMovable&&(j(v,r),F(v,s,"all")),a.cropBoxResizable||(j(f.getElementsByClassName(i+"-line"),n),j(f.getElementsByClassName(i+"-point"),n)),this.setDragMode(a.dragMode),this.render(),this.ready=!0,this.setData(a.data),this.completing=setTimeout(function(){X(a.ready)&&J(e,"ready",a.ready,{once:!0}),_(e,"ready"),_(e,l,t.getData()),t.complete=!0},0)}}},{key:"unbuild",value:function(){this.ready&&(this.complete||clearTimeout(this.completing),this.ready=!1,this.complete=!1,this.initialImageData=null,this.initialCanvasData=null,this.initialCropBoxData=null,this.containerData=null,this.canvasData=null,this.cropBoxData=null,this.unbind(),this.resetPreview(),this.previews=null,this.viewBox=null,this.cropBox=null,this.dragBox=null,this.canvas=null,this.container=null,this.cropper.parentNode.removeChild(this.cropper),this.cropper=null)}}],[{key:"noConflict",value:function(){return window.Cropper=bt,t}},{key:"setDefaults",value:function(t){S(M,Y(t)&&t)}}]),t}();return S(yt.prototype,ut,gt,ft,vt,wt,xt),yt}); \ No newline at end of file diff --git a/library/cropperjs/docs/css/cropper.css b/library/cropperjs/docs/css/cropper.css new file mode 100644 index 000000000..dd22178fe --- /dev/null +++ b/library/cropperjs/docs/css/cropper.css @@ -0,0 +1,306 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:26:29.610Z + */ + +.cropper-container { + direction: ltr; + font-size: 0; + line-height: 0; + position: relative; + -ms-touch-action: none; + touch-action: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.cropper-container img {/*Avoid margin top issue (Occur only when margin-top <= -height) + */ + display: block; + height: 100%; + image-orientation: 0deg; + max-height: none !important; + max-width: none !important; + min-height: 0 !important; + min-width: 0 !important; + width: 100%; +} + +.cropper-wrap-box, +.cropper-canvas, +.cropper-drag-box, +.cropper-crop-box, +.cropper-modal { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.cropper-wrap-box, +.cropper-canvas { + overflow: hidden; +} + +.cropper-drag-box { + background-color: #fff; + opacity: 0; +} + +.cropper-modal { + background-color: #000; + opacity: .5; +} + +.cropper-view-box { + display: block; + height: 100%; + outline-color: rgba(51, 153, 255, 0.75); + outline: 1px solid #39f; + overflow: hidden; + width: 100%; +} + +.cropper-dashed { + border: 0 dashed #eee; + display: block; + opacity: .5; + position: absolute; +} + +.cropper-dashed.dashed-h { + border-bottom-width: 1px; + border-top-width: 1px; + height: 33.33333%; + left: 0; + top: 33.33333%; + width: 100%; +} + +.cropper-dashed.dashed-v { + border-left-width: 1px; + border-right-width: 1px; + height: 100%; + left: 33.33333%; + top: 0; + width: 33.33333%; +} + +.cropper-center { + display: block; + height: 0; + left: 50%; + opacity: .75; + position: absolute; + top: 50%; + width: 0; +} + +.cropper-center:before, +.cropper-center:after { + background-color: #eee; + content: ' '; + display: block; + position: absolute; +} + +.cropper-center:before { + height: 1px; + left: -3px; + top: 0; + width: 7px; +} + +.cropper-center:after { + height: 7px; + left: 0; + top: -3px; + width: 1px; +} + +.cropper-face, +.cropper-line, +.cropper-point { + display: block; + height: 100%; + opacity: .1; + position: absolute; + width: 100%; +} + +.cropper-face { + background-color: #fff; + left: 0; + top: 0; +} + +.cropper-line { + background-color: #39f; +} + +.cropper-line.line-e { + cursor: ew-resize; + right: -3px; + top: 0; + width: 5px; +} + +.cropper-line.line-n { + cursor: ns-resize; + height: 5px; + left: 0; + top: -3px; +} + +.cropper-line.line-w { + cursor: ew-resize; + left: -3px; + top: 0; + width: 5px; +} + +.cropper-line.line-s { + bottom: -3px; + cursor: ns-resize; + height: 5px; + left: 0; +} + +.cropper-point { + background-color: #39f; + height: 5px; + opacity: .75; + width: 5px; +} + +.cropper-point.point-e { + cursor: ew-resize; + margin-top: -3px; + right: -3px; + top: 50%; +} + +.cropper-point.point-n { + cursor: ns-resize; + left: 50%; + margin-left: -3px; + top: -3px; +} + +.cropper-point.point-w { + cursor: ew-resize; + left: -3px; + margin-top: -3px; + top: 50%; +} + +.cropper-point.point-s { + bottom: -3px; + cursor: s-resize; + left: 50%; + margin-left: -3px; +} + +.cropper-point.point-ne { + cursor: nesw-resize; + right: -3px; + top: -3px; +} + +.cropper-point.point-nw { + cursor: nwse-resize; + left: -3px; + top: -3px; +} + +.cropper-point.point-sw { + bottom: -3px; + cursor: nesw-resize; + left: -3px; +} + +.cropper-point.point-se { + bottom: -3px; + cursor: nwse-resize; + height: 20px; + opacity: 1; + right: -3px; + width: 20px; +} + +@media (min-width: 768px) { + .cropper-point.point-se { + height: 15px; + width: 15px; + } +} + +@media (min-width: 992px) { + .cropper-point.point-se { + height: 10px; + width: 10px; + } +} + +@media (min-width: 1200px) { + .cropper-point.point-se { + height: 5px; + opacity: .75; + width: 5px; + } +} + +.cropper-point.point-se:before { + background-color: #39f; + bottom: -50%; + content: ' '; + display: block; + height: 200%; + opacity: 0; + position: absolute; + right: -50%; + width: 200%; +} + +.cropper-invisible { + opacity: 0; +} + +.cropper-bg { + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAQMAAAAlPW0iAAAAA3NCSVQICAjb4U/gAAAABlBMVEXMzMz////TjRV2AAAACXBIWXMAAArrAAAK6wGCiw1aAAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1M26LyyjAAAABFJREFUCJlj+M/AgBVhF/0PAH6/D/HkDxOGAAAAAElFTkSuQmCC'); +} + +.cropper-hide { + display: block; + height: 0; + position: absolute; + width: 0; +} + +.cropper-hidden { + display: none !important; +} + +.cropper-move { + cursor: move; +} + +.cropper-crop { + cursor: crosshair; +} + +.cropper-disabled .cropper-drag-box, +.cropper-disabled .cropper-face, +.cropper-disabled .cropper-line, +.cropper-disabled .cropper-point { + cursor: not-allowed; +} + diff --git a/library/cropperjs/docs/css/main.css b/library/cropperjs/docs/css/main.css new file mode 100644 index 000000000..d89f82d27 --- /dev/null +++ b/library/cropperjs/docs/css/main.css @@ -0,0 +1,252 @@ +.btn { + padding-left: .75rem; + padding-right: .75rem; +} + +label.btn { + margin-bottom: 0; +} + +.d-flex > .btn { + flex: 1; +} + +.carbonads { + border-radius: .25rem; + border: 1px solid #ccc; + font-size: .875rem; + overflow: hidden; + padding: 1rem; +} + +.carbon-wrap { + overflow: hidden; +} + +.carbon-img { + clear: left; + display: block; + float: left; +} + +.carbon-text, +.carbon-poweredby { + display: block; + margin-left: 140px; +} + +.carbon-text, +.carbon-text:hover, +.carbon-text:focus { + color: #fff; + text-decoration: none; +} + +.carbon-poweredby, +.carbon-poweredby:hover, +.carbon-poweredby:focus { + color: #ddd; + text-decoration: none; +} + +@media (min-width: 768px) { + .carbonads { + float: right; + margin-bottom: -1rem; + margin-top: -1rem; + max-width: 360px; + } +} + +.footer { + font-size: .875rem; +} + +.heart { + color: #ddd; + display: block; + height: 2rem; + line-height: 2rem; + margin-bottom: 0; + margin-top: 1rem; + position: relative; + text-align: center; + width: 100%; +} + +.heart:hover { + color: #ff4136; +} + +.heart::before { + border-top: 1px solid #eee; + content: " "; + display: block; + height: 0; + left: 0; + position: absolute; + right: 0; + top: 50%; +} + +.heart::after { + background-color: #fff; + content: "♥"; + padding-left: .5rem; + padding-right: .5rem; + position: relative; + z-index: 1; +} + +.img-container, +.img-preview { + background-color: #f7f7f7; + text-align: center; + width: 100%; +} + +.img-container { + margin-bottom: 1rem; + max-height: 497px; + min-height: 200px; +} + +@media (min-width: 768px) { + .img-container { + min-height: 497px; + } +} + +.img-container > img { + max-width: 100%; +} + +.docs-preview { + margin-right: -1rem; +} + +.img-preview { + float: left; + margin-bottom: .5rem; + margin-right: .5rem; + overflow: hidden; +} + +.img-preview > img { + max-width: 100%; +} + +.preview-lg { + height: 9rem; + width: 16rem; +} + +.preview-md { + height: 4.5rem; + width: 8rem; +} + +.preview-sm { + height: 2.25rem; + width: 4rem; +} + +.preview-xs { + height: 1.125rem; + margin-right: 0; + width: 2rem; +} + +.docs-data > .input-group { + margin-bottom: .5rem; +} + +.docs-data .input-group-prepend .input-group-text { + min-width: 4rem; +} + +.docs-data .input-group-append .input-group-text { + min-width: 3rem; +} + +.docs-buttons > .btn, +.docs-buttons > .btn-group, +.docs-buttons > .form-control { + margin-bottom: .5rem; + margin-right: .25rem; +} + +.docs-toggles > .btn, +.docs-toggles > .btn-group, +.docs-toggles > .dropdown { + margin-bottom: .5rem; +} + +.docs-tooltip { + display: block; + margin: -.5rem -.75rem; + padding: .5rem .75rem; +} + +.docs-tooltip > .icon { + margin: 0 -.25rem; + vertical-align: top; +} + +.tooltip-inner { + white-space: normal; +} + +.btn-upload .tooltip-inner, +.btn-toggle .tooltip-inner { + white-space: nowrap; +} + +.btn-toggle { + padding: .5rem; +} + +.btn-toggle > .docs-tooltip { + margin: -.5rem; + padding: .5rem; +} + +@media (max-width: 400px) { + .btn-group-crop { + margin-right: -1rem!important; + } + + .btn-group-crop > .btn { + padding-left: .5rem; + padding-right: .5rem; + } + + .btn-group-crop .docs-tooltip { + margin-left: -.5rem; + margin-right: -.5rem; + padding-left: .5rem; + padding-right: .5rem; + } +} + +.docs-options .dropdown-menu { + width: 100%; +} + +.docs-options .dropdown-menu > li { + font-size: .875rem; + padding: .125rem 1rem; +} + +.docs-options .dropdown-menu .form-check-label { + display: block; +} + +.docs-cropped .modal-body { + text-align: center; +} + +.docs-cropped .modal-body > img, +.docs-cropped .modal-body > canvas { + max-width: 100%; +} diff --git a/library/cropperjs/docs/images/data.jpg b/library/cropperjs/docs/images/data.jpg new file mode 100644 index 0000000000000000000000000000000000000000..56926a274d80ba3197d036645a9a9795f5f38677 GIT binary patch literal 16534 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 literal 0 HcmV?d00001 diff --git a/library/cropperjs/docs/images/layers.jpg b/library/cropperjs/docs/images/layers.jpg new file mode 100644 index 0000000000000000000000000000000000000000..02b77e7b2afcef789be940e444af43f522f3ca31 GIT binary patch literal 26921 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 bVib53gW0r$l$2a@a#+hz=dPahhv9z!%1KK! literal 0 HcmV?d00001 diff --git a/library/cropperjs/docs/images/picture-2.jpg b/library/cropperjs/docs/images/picture-2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..05df6dc31819a058455e49bdbfa9d47a47ab5f06 GIT binary patch literal 182998 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 VzfHY`6pSp=s_#+?w^XEW|JfH>e4PLQ literal 0 HcmV?d00001 diff --git a/library/cropperjs/docs/images/picture-3.jpg b/library/cropperjs/docs/images/picture-3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..472d721b6edd5334e48235a13e0675ea9fa1e7a9 GIT binary patch literal 224777 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 L0yU&*HO#Mfh3zw+3V zQ1boEaTp|MVjRAtYQ?@NWO%tD`yPe@u{2&Cr1?p;k1Rta*_tgdN@laWf+jIM$;dSn zucI2DvBm!Yc>e&l-?5dBZSxOG^B?@<-^cW+*hyIZcU1*+lk~~R#o(%lr+pE{ias*{{VPC)Ky**e~|pSVymxo=`KmQXqo5LA3<6}MFky!QQ%fpJzL{u;7P zRy)&Y%6Vi$@*jy|NVy}@r{ao8+tgJ4_8;$l&IMy1n0{W0($3^qQEhmVvCc|JJx3m| z)yr4=w+eYT#p!eOu}!;Q)~#2|)9KRbvc)ZmdeYfR7y=bMRC?Mz^H zSdOI&$$V$Nw=?=y(oH9;v~s&eR1On@EM*5F`&?Jz`**17QY82tIW`(p%gFj}lOLVD z+vHVgWYaaxHH=W)3QT8>KY9rMSj4oAzi*1=8AWc{icgnsZKk!jnhAG!U7;tqc$$P$ zw@k6Plzc2f4c4G>9_M_6bY9{4V>SF%I!DxR?ev??MJ{xC?r&l(Yv^+I{WfrZCY>AL zbM_s7X>w6%&Nq8E<%F?5fpG*{bJ+T9BfHcLl}o9)`YchJyd4spfcs6uj!bfKODWaN z7S^`%T*D>l`rJq6y3yiw6!gZsuw9S_9(a!6j$O4j!O0HmEInj`B>A`KKiqBp1= zOK%*U8;==27Wn=gRVni(kh-szOuC7cZ?yZRys`+PW&wDZ<5<4R%ju6xs%O@M@g zjPm2(eO60ryH&K*Egnc(6k#ARvk9YQZiSdP7O&fyH~pLnjJuNFDPBN|?$I|s1(dWL zs)~+B!WGSbn-x$nMfK;pV4=E1{6drj{?5n7ylKng_^>KpKA9A=+FVG}PWF>LvdHGH zo|;$Cm4$s+WJcx0{jb_=RbJ*<1nUe8<*&U+C7w`<03M@$@%a6g_^}G0&|68(tW%tKQb#1hzq{q}8C__9cGcqTGXB@Y z!{Wx35$VTo0D&%zz1s&dT{v|ZmzQp z!>cJ}^uR{%@i#0edA_l$!>?*@XJoG)g=ECt%`216MkN+B@_GG1EAGgOFWUQY(~1Bp}1r|n^oW?AxE zL46maa~PONs?$eS6``nFsjWG6URg28puI=Pn%&;1q)Trod9Gc!+)v4Pd?SL216B1^ zRaJh<`fV;vizf7y?V*ii92rf#vLuxOV{q}QVk%{lpB&Bpy8XOW53Adxe_B+65g(!T zh@n(iRi(FoUPNbKh${ja`3`T#6-3@3T}Iw}i9gdEdNE0ErNE7o)RCP?Eb%iBuzm&j z8{&V56>Z~;TFVu@pXpGVvvUrr;)m0gQA(wVTww~>Y|?%-AM~q zELxtQ6VLrzRjYe=BGX`kylv2`MhOK{I)XgOsX0If1P`C~8B(xl28n`{aAB&IeVyn*)EU~!+LFu%1zh(Ibb^X3AimIyy zX{wGLBT6isV}zC@B^VRQqyzT8E+~zPt-5lOEyTA)tY--futuQ7vMoWFNlr~(D3AP~ zX>cnaTNxy}xm`ibm$y@@PZU8NW`(K+dql9JuPX8X0A|?IQTA8UtlDk2r5J)qCP?Rj z+u%qAR*}e|$qC3e@_ZNyX@0u4tz#qxD#GdlsuvDO*%5fqQEDpsDID7mB)eaBSf@zHZZS{EIx$sBF8=^Cl3-sy{%9y)Fh<Oy9|ghgK;6069YikCi;BrQ4`6#bGC^L7^qcBvWp+`(Nc_lX_NR z`8Q{Eq^IPl}jzs>x=@VRukA?Kf$`Yp%&tSbj%rZ_}|9vn(4Mo2wA(=S4PEQAuAer}`} z+SE2hiFgqwonzw871!aaoxpz7%Oq$hXZ}Hg()aSde&#lKl3i5ai)2T>kn<}!1Fpc5*9*|54Ng4*S<+C<3d;$P7)`?&VeDQ zpfT5wuiuIubNQutdk(H5iB*NA3|9Q{{WPm zaAXJkn(cvE{1%M`q;`d>@kGIT142y>-{j#6U;owPV>(Az?)VkFRoJUot9Vt|tFc#M zLwFU~tFWuFR>msqRoJ24_^V?Tb}4TZIAX5Ct>8;|RX)%)-8ahGUH6)9tXlI^f>gEg z*Qvd--xMz-l8S;%5i&{qzZVbkvtO>%aE=gn{wFg_iuZYi=B23LUr(rA+%?7h%QH`L zAqAvn>JM%I0GBj^F4}V^a*h2NulkY1eHEHw0ERgdN2%Cy2wU#1GK4^~)f}@Xf^neaMv9*dQ zzQ3tl8)^}DmQs4B)B7q3<3s8G?fxI$D*RZ|p+7J`G#kruXfLKo6{nZATQhs7T-(9w z+1!UAo;e|>?)@%m{C*#|$)A=)-R#)_4>c_p{&EY-R+sSFYfybtk`}O^O@-uB>9J;r zt$2ifMfiV}{;m+lQK!y7m~G|w{OfKln|v>^`z?@fBE#&zD{CiQ^1hXNv+@w!1=OTk zNRlE%LJwBFndUlKFf|R#lP3Z zQi~a(wbUhsdwXB3!1H=?Ay6SeR810)1wI0<=_3Bu+QcbNA(;BHBiq0Gv5e_Pj1?60 z_B%VPE2r$g?ERc5UL-3Vvr%RBNSoqiQ5u>TDoAgOl^=hz{!S{~lG@zdPj1e#wH2jU znuR_fr;Dz~;scv~tWbuJQ$Jd_f-oSF;WIs}P|QgsYP_h_L&(VAXOADVilQZxmk}fl z>9t(ks}is>vaL59s!_h**>8$A#VRXtcJ|9V`f*7lk_gpV3~mYi+|*yS`?2;u-w(Hn zt0ZPck(6*tsyuOuvrt#}(XyY~0bNl40F}=bYQ$eGj`BY@nU+xrPBWQD+ATxElnTkm z6d|OF&J>>No}^{D5P&ksO9BuQDkx7TKkI)g;*__{I$KGmPXYlw(TFr$xiNFdl?X<` zB#Nq(;lcRx#a>h9H;+-$w9P_z84x^BCb1=0O&CDW43GA{2?8tf_+^!NN5_nuf4~OkH##7^c0`QYMtw;N zMwd4H7Fgp_e#uI5P1;B&MZ$&+s%jbnTijaC7T`@Kz_h)Q5lz5g9nxuGG>UIn{`nad zTl|IR#48AwQPi{zPRcKeXe~KOdv68Io}6&X%f!Tyu@Nz0!M!o|*Y=U|N@1dTs@*>~ zY&^wqSUv6BP(%wex7Dst!p$Qd0J=91Qi!U#UO{1$HZLvw=+Pq4KQz3@WgIOWLh#FO z4*viI;7QBnQrIEMxsBKrF@<4Lj8|_C*p}!Qr+FJuNiqgu9lX%X6}fV;tQ`1V zEB^qKBuo?ezmc#4oY30eM}A*ihnD{UN)Fn6o4UP+mu{AqHjpJGNoYyrwPd2#pC5}Y z4gqC%aNFuuvs&sViF@dL1%*+Whxc+V2;xy$WFKN*+QNh+HJfmN;O@)1Sm?aTaz{{UYVLhAOG zl0|1cwrvwmVzRlqRx!&0ab`zyq#0FY;5ajUKM(BkTv8NttxkDi)8e>j-%`{N&Bx*Z z#ZZXS1_SrZc(jO#`=8!_k%3WnNgcYVnnzb@7^3o{b6Pj1y*?FC)a8o0T_!2XSs1Fy zRLt@6D%4V{;FHOEkx4!YJ|)Faut6%t3oW>{Xlod^l#s0&{3IHZ%Jm=Ra#dbGYXYj9 zMui?Y8Dq4a8WiQo6D)*~TBL)KRbz7V0FDazT#&uUUkzGKKl$`!3<=n4M47@S5M#?=6PRZqrk#{V%sCc*TSchjq zYw)Ci^ZsAhTu_b*(#t$(O00-EOUM=sNCJVjuPP0`EK-;1_J5}>E-Yj+#VUVusHy;g zq$iTV3GAngpYv+rLQxNtbbDJt4df@BpSZNQiHVLlqFNH|@G<93ayR@J!;#@t4>fr| zO}{|4_K7SucI_Rv2N97gkXWRE2S=yISM0CZ{j3s*N=tL1{d`*5xk;n5oh9|84ze-` z$wVXtB1pexb^BS5J*4DgJ5$7b@27c&+s)U|*m`hFJ-l;V^KL3$)x8-Ua^Ing)cvj* zFw9jmO+HI`pm`%!5C!yERIpWkAh=GI-0b-%G)bKPSl&rtslJySq7ic#OIV2by8;D+W0J&QB%Cm-44&lO!N zMsF5S5T^O`C6S>i>JjG;#w#z9g0KeLLW5w8j5C#KRhJzqdjJ8~N%zUqNH@%Y=} zR>G|`Ya~J>KBTC{=zcnca(OTyG5G!j_<1k;917gC&FM%~D4%AejzS(yL&}D&@E?QW z`%Cd+s#Av^tVU&|WQM9Jkidqrl8S!MAA{BVO5e?jsoMHicD}5u8!T5c$8IBMDu|+y z)YIZ%hvI*+{J5)sR9UWGW#p5Brc&F6SiuQY_-GKwNArHq?BG=h#D?r29o=ftc7NdhsAwfPnKKTmWmF&kgtIFu}yA~3yphl5OhAk`5&~#dy zLJP*fG;ZdL&(~J=saBTOJ8}w_0bV*X@%@oS$&>`o^Ag-Ami)hdlbG%0#Y`s}nU#BgLT4+W)ovwxL? zszcX*GPQ`b?IX(xC6K&^2)?q=5m?#QE)l05gs(1X%lUF=k`iCbdk6mj6w7%psVdE5 z6~&Cw4m65-D{}|zxFM5?`#f=orAu#^>Yi)XuB_0)_eYZ4JZU^q`ZQRfla*N__-iMp z#lFrGmVRu9m;V4KwQG4?6%kK6NSzAG>cWBk$yNA5eU-x$JnQnUFAlGNs|in}phM|K zYLYv(P>>Bi6kc`yd`e!!s=Sj~%^YXq^kh^CQ$}i#M~i&0g?Rq}mprAeuD5RDK?;bd_Uyj<10&UW3-}=tAiT20i>y2{=*Sk73|;2*o(BWU(9*`8@HJPL9N6}DLJ5iFeNG;-0FEKdFs(ODyS~&DPP9RF zaWzsfl~r}6OM={JoPI7@w2=|qxY6|rLd^uQ%PqXajLn%GzC z7N`vm?K*J&SBLp>MWh-#a(LZ^z2(eOG-cW-B6*l@Nm#{L06bT(+4!=zAc}EBn@*Bi zD#mFnEL}Mod@QU37aM-Z^L?z54Pz$icG3s7RHaOR0X_UhN6R2wn4Od{tuEU4D=w*J$nJ^jM^{ zXEMdfIB{>Y9mHHqd|bU%`#7pFhX@eJeh^9&pl&L_?ck~KtEcjQ)+(Z193*Oq4c8~6 zWkX1^NASrcYA6_>YPEjcZ}xFj+>EKfPyy*oB2*lBf_?>3LH_`oaa9MJ>R(kML=rPb zQJ;`Thi*&iFdm%B$7cTkh5J~lsJntQ87|1u$SvZMMdCz`X&5BZfsfj6vd!>)yj3oi z7rD5C+Bprhkxv^;&MGGy__rTu&+g>ne$S_hq*^SUWmwbi+r|MwQt3uIN0)#i9iww} zNSA10Iq=2M!j8IAe>GIj{e?0Fv_J(8I{oQ@Vd4A5}GBy}5@WSBR1Mg5E~?Qi}sUVUaGoRLi51 zeqzKhaBkjr^Z0zX*M(O9$CKx0E!b}@z--wIx8uu|f*zIk|o!;1+ zFsKVn;A3mqKKDdQGfim`mr+gCi&+sh=X`gg9SgIk`D{~|*{e^vsiKu;=B%?yA&w?4 zj$@27Z0O3%wX4Y3&8F-lemq_y2h`X!kD>LbTM3EK_iJ#j zcK2`#D)M$BC>VSG+}nDpkp0)OuYXp6^Doqpxg;EfjJQ&h7##JxYxq`D{<~f{ufg>A z%rY`LKWQ7fz*t2B~gm-NX0`%G1|=6GLt z_?%?~FFfZO�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 literal 0 HcmV?d00001 diff --git a/library/cropperjs/docs/index.html b/library/cropperjs/docs/index.html new file mode 100644 index 000000000..7c3354cb1 --- /dev/null +++ b/library/cropperjs/docs/index.html @@ -0,0 +1,578 @@ + + + + + + + + + + Cropper.js + + + + + + + + + + + + +
    +
    +
    +
    +

    Cropper.js v1.2.2

    +

    JavaScript image cropper.

    +
    +
    +
    + +
    +
    +
    +
    +
    + + +
    +
    +
    + +
    + Picture +
    +
    +
    + +
    +
    +
    +
    +
    +
    + + + +
    +
    + + + + + + px + +
    +
    + + + + + + px + +
    +
    + + + + + + px + +
    +
    + + + + + + px + +
    +
    + + + + + + deg + +
    +
    + + + + +
    +
    + + + + +
    +
    +
    +
    +
    +
    + +
    + + +
    + +
    + + +
    + +
    + + + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + +
    + +
    + + + +
    + +
    + + + +
    + + + + + + + + + + + + + + + + + + +
    + +
    + +
    + + + + + +
    + +
    + + + + +
    + + + + Photo Editor + +
    +
    +
    + + + + + + + + + + + + diff --git a/library/cropperjs/docs/js/cropper.js b/library/cropperjs/docs/js/cropper.js new file mode 100644 index 000000000..0e837953c --- /dev/null +++ b/library/cropperjs/docs/js/cropper.js @@ -0,0 +1,3766 @@ +/*! + * Cropper.js v1.2.2 + * https://github.com/fengyuanchen/cropperjs + * + * Copyright (c) 2015-2018 Chen Fengyuan + * Released under the MIT license + * + * Date: 2018-01-03T13:27:18.062Z + */ + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.Cropper = factory()); +}(this, (function () { 'use strict'; + +var WINDOW = typeof window !== 'undefined' ? window : {}; +var NAMESPACE = 'cropper'; + +// Actions +var ACTION_ALL = 'all'; +var ACTION_CROP = 'crop'; +var ACTION_MOVE = 'move'; +var ACTION_ZOOM = 'zoom'; +var ACTION_EAST = 'e'; +var ACTION_WEST = 'w'; +var ACTION_SOUTH = 's'; +var ACTION_NORTH = 'n'; +var ACTION_NORTH_EAST = 'ne'; +var ACTION_NORTH_WEST = 'nw'; +var ACTION_SOUTH_EAST = 'se'; +var ACTION_SOUTH_WEST = 'sw'; + +// Classes +var CLASS_CROP = NAMESPACE + '-crop'; +var CLASS_DISABLED = NAMESPACE + '-disabled'; +var CLASS_HIDDEN = NAMESPACE + '-hidden'; +var CLASS_HIDE = NAMESPACE + '-hide'; +var CLASS_INVISIBLE = NAMESPACE + '-invisible'; +var CLASS_MODAL = NAMESPACE + '-modal'; +var CLASS_MOVE = NAMESPACE + '-move'; + +// Data keys +var DATA_ACTION = 'action'; +var DATA_PREVIEW = 'preview'; + +// Drag modes +var DRAG_MODE_CROP = 'crop'; +var DRAG_MODE_MOVE = 'move'; +var DRAG_MODE_NONE = 'none'; + +// Events +var EVENT_CROP = 'crop'; +var EVENT_CROP_END = 'cropend'; +var EVENT_CROP_MOVE = 'cropmove'; +var EVENT_CROP_START = 'cropstart'; +var EVENT_DBLCLICK = 'dblclick'; +var EVENT_ERROR = 'error'; +var EVENT_LOAD = 'load'; +var EVENT_POINTER_DOWN = WINDOW.PointerEvent ? 'pointerdown' : 'touchstart mousedown'; +var EVENT_POINTER_MOVE = WINDOW.PointerEvent ? 'pointermove' : 'touchmove mousemove'; +var EVENT_POINTER_UP = WINDOW.PointerEvent ? 'pointerup pointercancel' : 'touchend touchcancel mouseup'; +var EVENT_READY = 'ready'; +var EVENT_RESIZE = 'resize'; +var EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; +var EVENT_ZOOM = 'zoom'; + +// RegExps +var REGEXP_ACTIONS = /^(e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; +var REGEXP_DATA_URL = /^data:/; +var REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/; +var REGEXP_TAG_NAME = /^(img|canvas)$/i; + +var DEFAULTS = { + // Define the view mode of the cropper + viewMode: 0, // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + dragMode: DRAG_MODE_CROP, // 'crop', 'move' or 'none' + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A selector for adding extra containers to preview + preview: '', + + // Re-render the cropper when resize the window + responsive: true, + + // Restore the cropped area after resize the window + restore: true, + + // Check if the current image is a cross-origin image + checkCrossOrigin: true, + + // Check the current image's Exif Orientation information + checkOrientation: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by dragging touch + zoomOnTouch: true, + + // Enable to zoom the image by wheeling mouse + zoomOnWheel: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + toggleDragModeOnDblclick: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + ready: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null +}; + +var TEMPLATE = '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '
    ' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '
    ' + '
    '; + +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; +}; + + + + + + + + + + + +var classCallCheck = function (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 toConsumableArray = function (arr) { + if (Array.isArray(arr)) { + for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) arr2[i] = arr[i]; + + return arr2; + } else { + return Array.from(arr); + } +}; + +/** + * Check if the given value is not a number. + */ +var isNaN = Number.isNaN || WINDOW.isNaN; + +/** + * Check if the given value is a number. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a number, else `false`. + */ +function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +/** + * Check if the given value is undefined. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is undefined, else `false`. + */ +function isUndefined(value) { + return typeof value === 'undefined'; +} + +/** + * Check if the given value is an object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is an object, else `false`. + */ +function isObject(value) { + return (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object' && value !== null; +} + +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * Check if the given value is a plain object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a plain object, else `false`. + */ + +function isPlainObject(value) { + if (!isObject(value)) { + return false; + } + + try { + var _constructor = value.constructor; + var prototype = _constructor.prototype; + + + return _constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (e) { + return false; + } +} + +/** + * Check if the given value is a function. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a function, else `false`. + */ +function isFunction(value) { + return typeof value === 'function'; +} + +/** + * Iterate the given data. + * @param {*} data - The data to iterate. + * @param {Function} callback - The process function for each element. + * @returns {*} The original data. + */ +function each(data, callback) { + if (data && isFunction(callback)) { + if (Array.isArray(data) || isNumber(data.length) /* array-like */) { + var length = data.length; + + var i = void 0; + + for (i = 0; i < length; i += 1) { + if (callback.call(data, data[i], i, data) === false) { + break; + } + } + } else if (isObject(data)) { + Object.keys(data).forEach(function (key) { + callback.call(data, data[key], key, data); + }); + } + } + + return data; +} + +/** + * Extend the given object. + * @param {*} obj - The object to be extended. + * @param {*} args - The rest objects which will be merged to the first object. + * @returns {Object} The extended object. + */ +function extend(obj) { + for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { + args[_key - 1] = arguments[_key]; + } + + if (isObject(obj) && args.length > 0) { + if (Object.assign) { + return Object.assign.apply(Object, [obj].concat(args)); + } + + args.forEach(function (arg) { + if (isObject(arg)) { + Object.keys(arg).forEach(function (key) { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; +} + +/** + * Takes a function and returns a new one that will always have a particular context. + * @param {Function} fn - The target function. + * @param {Object} context - The new context for the function. + * @returns {boolean} The new function. + */ +function proxy(fn, context) { + for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { + args[_key2 - 2] = arguments[_key2]; + } + + return function () { + for (var _len3 = arguments.length, args2 = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args2[_key3] = arguments[_key3]; + } + + return fn.apply(context, args.concat(args2)); + }; +} + +var REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/i; + +/** + * Normalize decimal number. + * Check out {@link http://0.30000000000000004.com/ } + * @param {number} value - The value to normalize. + * @param {number} [times=100000000000] - The times for normalizing. + * @returns {number} Returns the normalized number. + */ +function normalizeDecimalNumber(value) { + var times = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 100000000000; + + return REGEXP_DECIMALS.test(value) ? Math.round(value * times) / times : value; +} + +var REGEXP_SUFFIX = /^(width|height|left|top|marginLeft|marginTop)$/; + +/** + * Apply styles to the given element. + * @param {Element} element - The target element. + * @param {Object} styles - The styles for applying. + */ +function setStyle(element, styles) { + var style = element.style; + + + each(styles, function (value, property) { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); +} + +/** + * Check if the given element has a special class. + * @param {Element} element - The element to check. + * @param {string} value - The class to search. + * @returns {boolean} Returns `true` if the special class was found. + */ +function hasClass(element, value) { + return element.classList ? element.classList.contains(value) : element.className.indexOf(value) > -1; +} + +/** + * Add classes to the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be added. + */ +function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + var className = element.className.trim(); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = className + ' ' + value; + } +} + +/** + * Remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be removed. + */ +function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } +} + +/** + * Add or remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be toggled. + * @param {boolean} added - Add only. + */ +function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, function (elem) { + toggleClass(elem, value, added); + }); + return; + } + + // IE10-11 doesn't support the second parameter of `classList.toggle` + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } +} + +var REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; + +/** + * Hyphenate the given value. + * @param {string} value - The value to hyphenate. + * @returns {string} The hyphenated value. + */ +function hyphenate(value) { + return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); +} + +/** + * Get data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to get. + * @returns {string} The data value. + */ +function getData(element, name) { + if (isObject(element[name])) { + return element[name]; + } else if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute('data-' + hyphenate(name)); +} + +/** + * Set data to the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to set. + * @param {string} data - The data value. + */ +function setData(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute('data-' + hyphenate(name), data); + } +} + +/** + * Remove data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to remove. + */ +function removeData(element, name) { + if (isObject(element[name])) { + try { + delete element[name]; + } catch (e) { + element[name] = null; + } + } else if (element.dataset) { + // #128 Safari not allows to delete dataset property + try { + delete element.dataset[name]; + } catch (e) { + element.dataset[name] = null; + } + } else { + element.removeAttribute('data-' + hyphenate(name)); + } +} + +var REGEXP_SPACES = /\s+/; + +/** + * Remove event listener from the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function removeListener(element, type, listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + removeListener(element, t, listener, options); + }); + return; + } + + if (element.removeEventListener) { + element.removeEventListener(type, listener, options); + } else if (element.detachEvent) { + element.detachEvent('on' + type, listener); + } +} + +/** + * Add event listener to the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +function addListener(element, type, _listener) { + var options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + if (!isFunction(_listener)) { + return; + } + + var types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, function (t) { + addListener(element, t, _listener, options); + }); + return; + } + + if (options.once) { + var originalListener = _listener; + + _listener = function listener() { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + removeListener(element, type, _listener, options); + return originalListener.apply(element, args); + }; + } + + if (element.addEventListener) { + element.addEventListener(type, _listener, options); + } else if (element.attachEvent) { + element.attachEvent('on' + type, _listener); + } +} + +/** + * Dispatch event on the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Object} data - The additional event data. + * @returns {boolean} Indicate if the event is default prevented or not. + */ +function dispatchEvent(element, type, data) { + if (element.dispatchEvent) { + var event = void 0; + + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (isFunction(Event) && isFunction(CustomEvent)) { + if (isUndefined(data)) { + event = new Event(type, { + bubbles: true, + cancelable: true + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } + } else if (isUndefined(data)) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent('on' + type); + } + + return true; +} + +/** + * Get the offset base on the document. + * @param {Element} element - The target element. + * @returns {Object} The offset data. + */ +function getOffset(element) { + var doc = document.documentElement; + var box = element.getBoundingClientRect(); + + return { + left: box.left + ((window.scrollX || doc && doc.scrollLeft || 0) - (doc && doc.clientLeft || 0)), + top: box.top + ((window.scrollY || doc && doc.scrollTop || 0) - (doc && doc.clientTop || 0)) + }; +} + +/** + * Empty an element. + * @param {Element} element - The element to empty. + */ +function empty(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +var location = WINDOW.location; + +var REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i; + +/** + * Check if the given URL is a cross origin URL. + * @param {string} url - The target URL. + * @returns {boolean} Returns `true` if the given URL is a cross origin URL, else `false`. + */ +function isCrossOriginURL(url) { + var parts = url.match(REGEXP_ORIGINS); + + return parts && (parts[1] !== location.protocol || parts[2] !== location.hostname || parts[3] !== location.port); +} + +/** + * Add timestamp to the given URL. + * @param {string} url - The target URL. + * @returns {string} The result URL. + */ +function addTimestamp(url) { + var timestamp = 'timestamp=' + new Date().getTime(); + + return url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp; +} + +/** + * Get transforms base on the given object. + * @param {Object} obj - The target object. + * @returns {string} A string contains transform values. + */ +function getTransforms(_ref) { + var rotate = _ref.rotate, + scaleX = _ref.scaleX, + scaleY = _ref.scaleY, + translateX = _ref.translateX, + translateY = _ref.translateY; + + var values = []; + + if (isNumber(translateX) && translateX !== 0) { + values.push('translateX(' + translateX + 'px)'); + } + + if (isNumber(translateY) && translateY !== 0) { + values.push('translateY(' + translateY + 'px)'); + } + + // Rotate should come first before scale to match orientation transform + if (isNumber(rotate) && rotate !== 0) { + values.push('rotate(' + rotate + 'deg)'); + } + + if (isNumber(scaleX) && scaleX !== 1) { + values.push('scaleX(' + scaleX + ')'); + } + + if (isNumber(scaleY) && scaleY !== 1) { + values.push('scaleY(' + scaleY + ')'); + } + + var transform = values.length ? values.join(' ') : 'none'; + + return { + WebkitTransform: transform, + msTransform: transform, + transform: transform + }; +} + +var navigator = WINDOW.navigator; + +var IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent); + +/** + * Get an image's natural sizes. + * @param {string} image - The target image. + * @param {Function} callback - The callback function. + */ +function getImageNaturalSizes(image, callback) { + // Modern browsers (except Safari) + if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) { + callback(image.naturalWidth, image.naturalHeight); + return; + } + + var newImage = document.createElement('img'); + var body = document.body || document.documentElement; + + newImage.onload = function () { + callback(newImage.width, newImage.height); + + if (!IS_SAFARI_OR_UIWEBVIEW) { + body.removeChild(newImage); + } + }; + + newImage.src = image.src; + + // iOS Safari will convert the image automatically + // with its orientation once append it into DOM (#279) + if (!IS_SAFARI_OR_UIWEBVIEW) { + newImage.style.cssText = 'left:0;' + 'max-height:none!important;' + 'max-width:none!important;' + 'min-height:0!important;' + 'min-width:0!important;' + 'opacity:0;' + 'position:absolute;' + 'top:0;' + 'z-index:-1;'; + body.appendChild(newImage); + } +} + +/** + * Get the max ratio of a group of pointers. + * @param {string} pointers - The target pointers. + * @returns {number} The result ratio. + */ +function getMaxZoomRatio(pointers) { + var pointers2 = extend({}, pointers); + var ratios = []; + + each(pointers, function (pointer, pointerId) { + delete pointers2[pointerId]; + + each(pointers2, function (pointer2) { + var x1 = Math.abs(pointer.startX - pointer2.startX); + var y1 = Math.abs(pointer.startY - pointer2.startY); + var x2 = Math.abs(pointer.endX - pointer2.endX); + var y2 = Math.abs(pointer.endY - pointer2.endY); + var z1 = Math.sqrt(x1 * x1 + y1 * y1); + var z2 = Math.sqrt(x2 * x2 + y2 * y2); + var ratio = (z2 - z1) / z1; + + ratios.push(ratio); + }); + }); + + ratios.sort(function (a, b) { + return Math.abs(a) < Math.abs(b); + }); + + return ratios[0]; +} + +/** + * Get a pointer from an event object. + * @param {Object} event - The target event object. + * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not. + * @returns {Object} The result pointer contains start and/or end point coordinates. + */ +function getPointer(_ref2, endOnly) { + var pageX = _ref2.pageX, + pageY = _ref2.pageY; + + var end = { + endX: pageX, + endY: pageY + }; + + if (endOnly) { + return end; + } + + return extend({ + startX: pageX, + startY: pageY + }, end); +} + +/** + * Get the center point coordinate of a group of pointers. + * @param {Object} pointers - The target pointers. + * @returns {Object} The center point coordinate. + */ +function getPointersCenter(pointers) { + var pageX = 0; + var pageY = 0; + var count = 0; + + each(pointers, function (_ref3) { + var startX = _ref3.startX, + startY = _ref3.startY; + + pageX += startX; + pageY += startY; + count += 1; + }); + + pageX /= count; + pageY /= count; + + return { + pageX: pageX, + pageY: pageY + }; +} + +/** + * Check if the given value is a finite number. + */ +var isFinite = Number.isFinite || WINDOW.isFinite; + +/** + * Get the max sizes in a rectangle under the given aspect ratio. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getContainSizes(_ref4) { + var aspectRatio = _ref4.aspectRatio, + height = _ref4.height, + width = _ref4.width; + + var isValidNumber = function isValidNumber(value) { + return isFinite(value) && value > 0; + }; + + if (isValidNumber(width) && isValidNumber(height)) { + if (height * aspectRatio > width) { + height = width / aspectRatio; + } else { + width = height * aspectRatio; + } + } else if (isValidNumber(width)) { + height = width / aspectRatio; + } else if (isValidNumber(height)) { + width = height * aspectRatio; + } + + return { + width: width, + height: height + }; +} + +/** + * Get the new sizes of a rectangle after rotated. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +function getRotatedSizes(_ref5) { + var width = _ref5.width, + height = _ref5.height, + degree = _ref5.degree; + + degree = Math.abs(degree) % 180; + + if (degree === 90) { + return { + width: height, + height: width + }; + } + + var arc = degree % 90 * Math.PI / 180; + var sinArc = Math.sin(arc); + var cosArc = Math.cos(arc); + var newWidth = width * cosArc + height * sinArc; + var newHeight = width * sinArc + height * cosArc; + + return degree > 90 ? { + width: newHeight, + height: newWidth + } : { + width: newWidth, + height: newHeight + }; +} + +/** + * Get a canvas which drew the given image. + * @param {HTMLImageElement} image - The image for drawing. + * @param {Object} imageData - The image data. + * @param {Object} canvasData - The canvas data. + * @param {Object} options - The options. + * @returns {HTMLCanvasElement} The result canvas. + */ +function getSourceCanvas(image, _ref6, _ref7, _ref8) { + var imageNaturalWidth = _ref6.naturalWidth, + imageNaturalHeight = _ref6.naturalHeight, + _ref6$rotate = _ref6.rotate, + rotate = _ref6$rotate === undefined ? 0 : _ref6$rotate, + _ref6$scaleX = _ref6.scaleX, + scaleX = _ref6$scaleX === undefined ? 1 : _ref6$scaleX, + _ref6$scaleY = _ref6.scaleY, + scaleY = _ref6$scaleY === undefined ? 1 : _ref6$scaleY; + var aspectRatio = _ref7.aspectRatio, + naturalWidth = _ref7.naturalWidth, + naturalHeight = _ref7.naturalHeight; + var _ref8$fillColor = _ref8.fillColor, + fillColor = _ref8$fillColor === undefined ? 'transparent' : _ref8$fillColor, + _ref8$imageSmoothingE = _ref8.imageSmoothingEnabled, + imageSmoothingEnabled = _ref8$imageSmoothingE === undefined ? true : _ref8$imageSmoothingE, + _ref8$imageSmoothingQ = _ref8.imageSmoothingQuality, + imageSmoothingQuality = _ref8$imageSmoothingQ === undefined ? 'low' : _ref8$imageSmoothingQ, + _ref8$maxWidth = _ref8.maxWidth, + maxWidth = _ref8$maxWidth === undefined ? Infinity : _ref8$maxWidth, + _ref8$maxHeight = _ref8.maxHeight, + maxHeight = _ref8$maxHeight === undefined ? Infinity : _ref8$maxHeight, + _ref8$minWidth = _ref8.minWidth, + minWidth = _ref8$minWidth === undefined ? 0 : _ref8$minWidth, + _ref8$minHeight = _ref8.minHeight, + minHeight = _ref8$minHeight === undefined ? 0 : _ref8$minHeight; + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: maxWidth, + height: maxHeight + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minWidth, + height: minHeight + }); + var width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth)); + var height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight)); + var params = [-imageNaturalWidth / 2, -imageNaturalHeight / 2, imageNaturalWidth, imageNaturalHeight]; + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + context.fillStyle = fillColor; + context.fillRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + context.rotate(rotate * Math.PI / 180); + context.scale(scaleX, scaleY); + context.imageSmoothingEnabled = imageSmoothingEnabled; + context.imageSmoothingQuality = imageSmoothingQuality; + context.drawImage.apply(context, [image].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + context.restore(); + return canvas; +} + +var fromCharCode = String.fromCharCode; + +/** + * Get string from char code in data view. + * @param {DataView} dataView - The data view for read. + * @param {number} start - The start index. + * @param {number} length - The read length. + * @returns {string} The read result. + */ + +function getStringFromCharCode(dataView, start, length) { + var str = ''; + var i = void 0; + + length += start; + + for (i = start; i < length; i += 1) { + str += fromCharCode(dataView.getUint8(i)); + } + + return str; +} + +var REGEXP_DATA_URL_HEAD = /^data:.*,/; + +/** + * Transform Data URL to array buffer. + * @param {string} dataURL - The Data URL to transform. + * @returns {ArrayBuffer} The result array buffer. + */ +function dataURLToArrayBuffer(dataURL) { + var base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); + var binary = atob(base64); + var arrayBuffer = new ArrayBuffer(binary.length); + var uint8 = new Uint8Array(arrayBuffer); + + each(uint8, function (value, i) { + uint8[i] = binary.charCodeAt(i); + }); + + return arrayBuffer; +} + +/** + * Transform array buffer to Data URL. + * @param {ArrayBuffer} arrayBuffer - The array buffer to transform. + * @param {string} mimeType - The mime type of the Data URL. + * @returns {string} The result Data URL. + */ +function arrayBufferToDataURL(arrayBuffer, mimeType) { + var uint8 = new Uint8Array(arrayBuffer); + var data = ''; + + // TypedArray.prototype.forEach is not supported in some browsers. + each(uint8, function (value) { + data += fromCharCode(value); + }); + + return 'data:' + mimeType + ';base64,' + btoa(data); +} + +/** + * Get orientation value from given array buffer. + * @param {ArrayBuffer} arrayBuffer - The array buffer to read. + * @returns {number} The read orientation value. + */ +function getOrientation(arrayBuffer) { + var dataView = new DataView(arrayBuffer); + var orientation = void 0; + var littleEndian = void 0; + var app1Start = void 0; + var ifdStart = void 0; + + // Only handle JPEG image (start by 0xFFD8) + if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { + var length = dataView.byteLength; + var offset = 2; + + while (offset < length) { + if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { + app1Start = offset; + break; + } + + offset += 1; + } + } + + if (app1Start) { + var exifIDCode = app1Start + 4; + var tiffOffset = app1Start + 10; + + if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { + var endianness = dataView.getUint16(tiffOffset); + + littleEndian = endianness === 0x4949; + + if (littleEndian || endianness === 0x4D4D /* bigEndian */) { + if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { + var firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); + + if (firstIFDOffset >= 0x00000008) { + ifdStart = tiffOffset + firstIFDOffset; + } + } + } + } + } + + if (ifdStart) { + var _length = dataView.getUint16(ifdStart, littleEndian); + var _offset = void 0; + var i = void 0; + + for (i = 0; i < _length; i += 1) { + _offset = ifdStart + i * 12 + 2; + + if (dataView.getUint16(_offset, littleEndian) === 0x0112 /* Orientation */) { + // 8 is the offset of the current tag's value + _offset += 8; + + // Get the original orientation value + orientation = dataView.getUint16(_offset, littleEndian); + + // Override the orientation with its default value + dataView.setUint16(_offset, 1, littleEndian); + break; + } + } + } + + return orientation; +} + +/** + * Parse Exif Orientation value. + * @param {number} orientation - The orientation to parse. + * @returns {Object} The parsed result. + */ +function parseOrientation(orientation) { + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + switch (orientation) { + // Flip horizontal + case 2: + scaleX = -1; + break; + + // Rotate left 180° + case 3: + rotate = -180; + break; + + // Flip vertical + case 4: + scaleY = -1; + break; + + // Flip vertical and rotate right 90° + case 5: + rotate = 90; + scaleY = -1; + break; + + // Rotate right 90° + case 6: + rotate = 90; + break; + + // Flip horizontal and rotate right 90° + case 7: + rotate = 90; + scaleX = -1; + break; + + // Rotate left 90° + case 8: + rotate = -90; + break; + + default: + } + + return { + rotate: rotate, + scaleX: scaleX, + scaleY: scaleY + }; +} + +var render = { + render: function render() { + this.initContainer(); + this.initCanvas(); + this.initCropBox(); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + }, + initContainer: function initContainer() { + var element = this.element, + options = this.options, + container = this.container, + cropper = this.cropper; + + + addClass(cropper, CLASS_HIDDEN); + removeClass(element, CLASS_HIDDEN); + + var containerData = { + width: Math.max(container.offsetWidth, Number(options.minContainerWidth) || 200), + height: Math.max(container.offsetHeight, Number(options.minContainerHeight) || 100) + }; + + this.containerData = containerData; + + setStyle(cropper, { + width: containerData.width, + height: containerData.height + }); + + addClass(element, CLASS_HIDDEN); + removeClass(cropper, CLASS_HIDDEN); + }, + + + // Canvas (image wrapper) + initCanvas: function initCanvas() { + var containerData = this.containerData, + imageData = this.imageData; + var viewMode = this.options.viewMode; + + var rotated = Math.abs(imageData.rotate) % 180 === 90; + var naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth; + var naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight; + var aspectRatio = naturalWidth / naturalHeight; + var canvasWidth = containerData.width; + var canvasHeight = containerData.height; + + if (containerData.height * aspectRatio > containerData.width) { + if (viewMode === 3) { + canvasWidth = containerData.height * aspectRatio; + } else { + canvasHeight = containerData.width / aspectRatio; + } + } else if (viewMode === 3) { + canvasHeight = containerData.width / aspectRatio; + } else { + canvasWidth = containerData.height * aspectRatio; + } + + var canvasData = { + aspectRatio: aspectRatio, + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + width: canvasWidth, + height: canvasHeight + }; + + canvasData.left = (containerData.width - canvasWidth) / 2; + canvasData.top = (containerData.height - canvasHeight) / 2; + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + this.canvasData = canvasData; + this.limited = viewMode === 1 || viewMode === 2; + this.limitCanvas(true, true); + this.initialImageData = extend({}, imageData); + this.initialCanvasData = extend({}, canvasData); + }, + limitCanvas: function limitCanvas(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var viewMode = options.viewMode; + var aspectRatio = canvasData.aspectRatio; + + var cropped = this.cropped && cropBoxData; + + if (sizeLimited) { + var minCanvasWidth = Number(options.minCanvasWidth) || 0; + var minCanvasHeight = Number(options.minCanvasHeight) || 0; + + if (viewMode > 1) { + minCanvasWidth = Math.max(minCanvasWidth, containerData.width); + minCanvasHeight = Math.max(minCanvasHeight, containerData.height); + + if (viewMode === 3) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } else if (viewMode > 0) { + if (minCanvasWidth) { + minCanvasWidth = Math.max(minCanvasWidth, cropped ? cropBoxData.width : 0); + } else if (minCanvasHeight) { + minCanvasHeight = Math.max(minCanvasHeight, cropped ? cropBoxData.height : 0); + } else if (cropped) { + minCanvasWidth = cropBoxData.width; + minCanvasHeight = cropBoxData.height; + + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: minCanvasWidth, + height: minCanvasHeight + }); + + minCanvasWidth = _getContainSizes.width; + minCanvasHeight = _getContainSizes.height; + + + canvasData.minWidth = minCanvasWidth; + canvasData.minHeight = minCanvasHeight; + canvasData.maxWidth = Infinity; + canvasData.maxHeight = Infinity; + } + + if (positionLimited) { + if (viewMode) { + var newCanvasLeft = containerData.width - canvasData.width; + var newCanvasTop = containerData.height - canvasData.height; + + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + canvasData.maxTop = Math.max(0, newCanvasTop); + + if (cropped && this.limited) { + canvasData.minLeft = Math.min(cropBoxData.left, cropBoxData.left + (cropBoxData.width - canvasData.width)); + canvasData.minTop = Math.min(cropBoxData.top, cropBoxData.top + (cropBoxData.height - canvasData.height)); + canvasData.maxLeft = cropBoxData.left; + canvasData.maxTop = cropBoxData.top; + + if (viewMode === 2) { + if (canvasData.width >= containerData.width) { + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + } + + if (canvasData.height >= containerData.height) { + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxTop = Math.max(0, newCanvasTop); + } + } + } + } else { + canvasData.minLeft = -canvasData.width; + canvasData.minTop = -canvasData.height; + canvasData.maxLeft = containerData.width; + canvasData.maxTop = containerData.height; + } + } + }, + renderCanvas: function renderCanvas(changed, transformed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + + if (transformed) { + var _getRotatedSizes = getRotatedSizes({ + width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1), + height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1), + degree: imageData.rotate || 0 + }), + naturalWidth = _getRotatedSizes.width, + naturalHeight = _getRotatedSizes.height; + + var width = canvasData.width * (naturalWidth / canvasData.naturalWidth); + var height = canvasData.height * (naturalHeight / canvasData.naturalHeight); + + canvasData.left -= (width - canvasData.width) / 2; + canvasData.top -= (height - canvasData.height) / 2; + canvasData.width = width; + canvasData.height = height; + canvasData.aspectRatio = naturalWidth / naturalHeight; + canvasData.naturalWidth = naturalWidth; + canvasData.naturalHeight = naturalHeight; + this.limitCanvas(true, false); + } + + if (canvasData.width > canvasData.maxWidth || canvasData.width < canvasData.minWidth) { + canvasData.left = canvasData.oldLeft; + } + + if (canvasData.height > canvasData.maxHeight || canvasData.height < canvasData.minHeight) { + canvasData.top = canvasData.oldTop; + } + + canvasData.width = Math.min(Math.max(canvasData.width, canvasData.minWidth), canvasData.maxWidth); + canvasData.height = Math.min(Math.max(canvasData.height, canvasData.minHeight), canvasData.maxHeight); + + this.limitCanvas(false, true); + + canvasData.left = Math.min(Math.max(canvasData.left, canvasData.minLeft), canvasData.maxLeft); + canvasData.top = Math.min(Math.max(canvasData.top, canvasData.minTop), canvasData.maxTop); + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + setStyle(this.canvas, extend({ + width: canvasData.width, + height: canvasData.height + }, getTransforms({ + translateX: canvasData.left, + translateY: canvasData.top + }))); + + this.renderImage(changed); + + if (this.cropped && this.limited) { + this.limitCropBox(true, true); + } + }, + renderImage: function renderImage(changed) { + var canvasData = this.canvasData, + imageData = this.imageData; + + var width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth); + var height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight); + + extend(imageData, { + width: width, + height: height, + left: (canvasData.width - width) / 2, + top: (canvasData.height - height) / 2 + }); + setStyle(this.image, extend({ + width: imageData.width, + height: imageData.height + }, getTransforms(extend({ + translateX: imageData.left, + translateY: imageData.top + }, imageData)))); + + if (changed) { + this.output(); + } + }, + initCropBox: function initCropBox() { + var options = this.options, + canvasData = this.canvasData; + var aspectRatio = options.aspectRatio; + + var autoCropArea = Number(options.autoCropArea) || 0.8; + var cropBoxData = { + width: canvasData.width, + height: canvasData.height + }; + + if (aspectRatio) { + if (canvasData.height * aspectRatio > canvasData.width) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.cropBoxData = cropBoxData; + this.limitCropBox(true, true); + + // Initialize auto crop area + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + // The width/height of auto crop area must large than "minWidth/Height" + cropBoxData.width = Math.max(cropBoxData.minWidth, cropBoxData.width * autoCropArea); + cropBoxData.height = Math.max(cropBoxData.minHeight, cropBoxData.height * autoCropArea); + cropBoxData.left = canvasData.left + (canvasData.width - cropBoxData.width) / 2; + cropBoxData.top = canvasData.top + (canvasData.height - cropBoxData.height) / 2; + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + this.initialCropBoxData = extend({}, cropBoxData); + }, + limitCropBox: function limitCropBox(sizeLimited, positionLimited) { + var options = this.options, + containerData = this.containerData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData, + limited = this.limited; + var aspectRatio = options.aspectRatio; + + + if (sizeLimited) { + var minCropBoxWidth = Number(options.minCropBoxWidth) || 0; + var minCropBoxHeight = Number(options.minCropBoxHeight) || 0; + var maxCropBoxWidth = Math.min(containerData.width, limited ? canvasData.width : containerData.width); + var maxCropBoxHeight = Math.min(containerData.height, limited ? canvasData.height : containerData.height); + + // The min/maxCropBoxWidth/Height must be less than container's width/height + minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width); + minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height); + + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } + } + + // The minWidth/Height must be less than maxWidth/Height + cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth); + cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight); + cropBoxData.maxWidth = maxCropBoxWidth; + cropBoxData.maxHeight = maxCropBoxHeight; + } + + if (positionLimited) { + if (limited) { + cropBoxData.minLeft = Math.max(0, canvasData.left); + cropBoxData.minTop = Math.max(0, canvasData.top); + cropBoxData.maxLeft = Math.min(containerData.width, canvasData.left + canvasData.width) - cropBoxData.width; + cropBoxData.maxTop = Math.min(containerData.height, canvasData.top + canvasData.height) - cropBoxData.height; + } else { + cropBoxData.minLeft = 0; + cropBoxData.minTop = 0; + cropBoxData.maxLeft = containerData.width - cropBoxData.width; + cropBoxData.maxTop = containerData.height - cropBoxData.height; + } + } + }, + renderCropBox: function renderCropBox() { + var options = this.options, + containerData = this.containerData, + cropBoxData = this.cropBoxData; + + + if (cropBoxData.width > cropBoxData.maxWidth || cropBoxData.width < cropBoxData.minWidth) { + cropBoxData.left = cropBoxData.oldLeft; + } + + if (cropBoxData.height > cropBoxData.maxHeight || cropBoxData.height < cropBoxData.minHeight) { + cropBoxData.top = cropBoxData.oldTop; + } + + cropBoxData.width = Math.min(Math.max(cropBoxData.width, cropBoxData.minWidth), cropBoxData.maxWidth); + cropBoxData.height = Math.min(Math.max(cropBoxData.height, cropBoxData.minHeight), cropBoxData.maxHeight); + + this.limitCropBox(false, true); + + cropBoxData.left = Math.min(Math.max(cropBoxData.left, cropBoxData.minLeft), cropBoxData.maxLeft); + cropBoxData.top = Math.min(Math.max(cropBoxData.top, cropBoxData.minTop), cropBoxData.maxTop); + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + if (options.movable && options.cropBoxMovable) { + // Turn to move the canvas when the crop box is equal to the container + setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width && cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL); + } + + setStyle(this.cropBox, extend({ + width: cropBoxData.width, + height: cropBoxData.height + }, getTransforms({ + translateX: cropBoxData.left, + translateY: cropBoxData.top + }))); + + if (this.cropped && this.limited) { + this.limitCanvas(true, true); + } + + if (!this.disabled) { + this.output(); + } + }, + output: function output() { + this.preview(); + + if (this.complete) { + dispatchEvent(this.element, EVENT_CROP, this.getData()); + } + } +}; + +var preview = { + initPreview: function initPreview() { + var crossOrigin = this.crossOrigin; + var preview = this.options.preview; + + var url = crossOrigin ? this.crossOriginUrl : this.url; + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = url; + this.viewBox.appendChild(image); + this.image2 = image; + + if (!preview) { + return; + } + + var previews = preview.querySelector ? [preview] : document.querySelectorAll(preview); + + this.previews = previews; + + each(previews, function (element) { + var img = document.createElement('img'); + + // Save the original size for recover + setData(element, DATA_PREVIEW, { + width: element.offsetWidth, + height: element.offsetHeight, + html: element.innerHTML + }); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * Add `height:auto` to override `height` attribute on IE8 + * (Occur only when margin-top <= -height) + */ + img.style.cssText = 'display:block;' + 'width:100%;' + 'height:auto;' + 'min-width:0!important;' + 'min-height:0!important;' + 'max-width:none!important;' + 'max-height:none!important;' + 'image-orientation:0deg!important;"'; + + empty(element); + element.appendChild(img); + }); + }, + resetPreview: function resetPreview() { + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + + setStyle(element, { + width: data.width, + height: data.height + }); + + element.innerHTML = data.html; + removeData(element, DATA_PREVIEW); + }); + }, + preview: function preview() { + var imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + var cropBoxWidth = cropBoxData.width, + cropBoxHeight = cropBoxData.height; + var width = imageData.width, + height = imageData.height; + + var left = cropBoxData.left - canvasData.left - imageData.left; + var top = cropBoxData.top - canvasData.top - imageData.top; + + if (!this.cropped || this.disabled) { + return; + } + + setStyle(this.image2, extend({ + width: width, + height: height + }, getTransforms(extend({ + translateX: -left, + translateY: -top + }, imageData)))); + + each(this.previews, function (element) { + var data = getData(element, DATA_PREVIEW); + var originalWidth = data.width; + var originalHeight = data.height; + var newWidth = originalWidth; + var newHeight = originalHeight; + var ratio = 1; + + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; + } + + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } + + setStyle(element, { + width: newWidth, + height: newHeight + }); + + setStyle(element.getElementsByTagName('img')[0], extend({ + width: width * ratio, + height: height * ratio + }, getTransforms(extend({ + translateX: -left * ratio, + translateY: -top * ratio + }, imageData)))); + }); + } +}; + +var events = { + bind: function bind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + addListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + addListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + addListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + addListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom); + } + + addListener(cropper, EVENT_POINTER_DOWN, this.onCropStart = proxy(this.cropStart, this)); + + if (options.zoomable && options.zoomOnWheel) { + addListener(cropper, EVENT_WHEEL, this.onWheel = proxy(this.wheel, this)); + } + + if (options.toggleDragModeOnDblclick) { + addListener(cropper, EVENT_DBLCLICK, this.onDblclick = proxy(this.dblclick, this)); + } + + addListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove = proxy(this.cropMove, this)); + addListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd = proxy(this.cropEnd, this)); + + if (options.responsive) { + addListener(window, EVENT_RESIZE, this.onResize = proxy(this.resize, this)); + } + }, + unbind: function unbind() { + var element = this.element, + options = this.options, + cropper = this.cropper; + + + if (isFunction(options.cropstart)) { + removeListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + removeListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + removeListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + removeListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + removeListener(element, EVENT_ZOOM, options.zoom); + } + + removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart); + + if (options.zoomable && options.zoomOnWheel) { + removeListener(cropper, EVENT_WHEEL, this.onWheel); + } + + if (options.toggleDragModeOnDblclick) { + removeListener(cropper, EVENT_DBLCLICK, this.onDblclick); + } + + removeListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove); + removeListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd); + + if (options.responsive) { + removeListener(window, EVENT_RESIZE, this.onResize); + } + } +}; + +var handlers = { + resize: function resize() { + var options = this.options, + container = this.container, + containerData = this.containerData; + + var minContainerWidth = Number(options.minContainerWidth) || 200; + var minContainerHeight = Number(options.minContainerHeight) || 100; + + if (this.disabled || containerData.width <= minContainerWidth || containerData.height <= minContainerHeight) { + return; + } + + var ratio = container.offsetWidth / containerData.width; + + // Resize when width changed or height changed + if (ratio !== 1 || container.offsetHeight !== containerData.height) { + var canvasData = void 0; + var cropBoxData = void 0; + + if (options.restore) { + canvasData = this.getCanvasData(); + cropBoxData = this.getCropBoxData(); + } + + this.render(); + + if (options.restore) { + this.setCanvasData(each(canvasData, function (n, i) { + canvasData[i] = n * ratio; + })); + this.setCropBoxData(each(cropBoxData, function (n, i) { + cropBoxData[i] = n * ratio; + })); + } + } + }, + dblclick: function dblclick() { + if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) { + return; + } + + this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP); + }, + wheel: function wheel(e) { + var _this = this; + + var ratio = Number(this.options.wheelZoomRatio) || 0.1; + var delta = 1; + + if (this.disabled) { + return; + } + + e.preventDefault(); + + // Limit wheel speed to prevent zoom too fast (#21) + if (this.wheeling) { + return; + } + + this.wheeling = true; + + setTimeout(function () { + _this.wheeling = false; + }, 50); + + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + this.zoom(-delta * ratio, e); + }, + cropStart: function cropStart(e) { + if (this.disabled) { + return; + } + + var options = this.options, + pointers = this.pointers; + + var action = void 0; + + if (e.changedTouches) { + // Handle touch event + each(e.changedTouches, function (touch) { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + // Handle mouse event and pointer event + pointers[e.pointerId || 0] = getPointer(e); + } + + if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { + action = ACTION_ZOOM; + } else { + action = getData(e.target, DATA_ACTION); + } + + if (!REGEXP_ACTIONS.test(action)) { + return; + } + + if (dispatchEvent(this.element, EVENT_CROP_START, { + originalEvent: e, + action: action + }) === false) { + return; + } + + e.preventDefault(); + + this.action = action; + this.cropping = false; + + if (action === ACTION_CROP) { + this.cropping = true; + addClass(this.dragBox, CLASS_MODAL); + } + }, + cropMove: function cropMove(e) { + var action = this.action; + + + if (this.disabled || !action) { + return; + } + + var pointers = this.pointers; + + + e.preventDefault(); + + if (dispatchEvent(this.element, EVENT_CROP_MOVE, { + originalEvent: e, + action: action + }) === false) { + return; + } + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + extend(pointers[touch.identifier], getPointer(touch, true)); + }); + } else { + extend(pointers[e.pointerId || 0], getPointer(e, true)); + } + + this.change(e); + }, + cropEnd: function cropEnd(e) { + if (this.disabled) { + return; + } + + var action = this.action, + pointers = this.pointers; + + + if (e.changedTouches) { + each(e.changedTouches, function (touch) { + delete pointers[touch.identifier]; + }); + } else { + delete pointers[e.pointerId || 0]; + } + + if (!action) { + return; + } + + e.preventDefault(); + + if (!Object.keys(pointers).length) { + this.action = ''; + } + + if (this.cropping) { + this.cropping = false; + toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal); + } + + dispatchEvent(this.element, EVENT_CROP_END, { + originalEvent: e, + action: action + }); + } +}; + +var change = { + change: function change(e) { + var options = this.options, + canvasData = this.canvasData, + containerData = this.containerData, + cropBoxData = this.cropBoxData, + pointers = this.pointers; + var action = this.action; + var aspectRatio = options.aspectRatio; + var left = cropBoxData.left, + top = cropBoxData.top, + width = cropBoxData.width, + height = cropBoxData.height; + + var right = left + width; + var bottom = top + height; + var minLeft = 0; + var minTop = 0; + var maxWidth = containerData.width; + var maxHeight = containerData.height; + var renderable = true; + var offset = void 0; + + // Locking aspect ratio in "free mode" by holding shift key + if (!aspectRatio && e.shiftKey) { + aspectRatio = width && height ? width / height : 1; + } + + if (this.limited) { + minLeft = cropBoxData.minLeft; + minTop = cropBoxData.minTop; + + maxWidth = minLeft + Math.min(containerData.width, canvasData.width, canvasData.left + canvasData.width); + maxHeight = minTop + Math.min(containerData.height, canvasData.height, canvasData.top + canvasData.height); + } + + var pointer = pointers[Object.keys(pointers)[0]]; + var range = { + x: pointer.endX - pointer.startX, + y: pointer.endY - pointer.startY + }; + var check = function check(side) { + switch (side) { + case ACTION_EAST: + if (right + range.x > maxWidth) { + range.x = maxWidth - right; + } + + break; + + case ACTION_WEST: + if (left + range.x < minLeft) { + range.x = minLeft - left; + } + + break; + + case ACTION_NORTH: + if (top + range.y < minTop) { + range.y = minTop - top; + } + + break; + + case ACTION_SOUTH: + if (bottom + range.y > maxHeight) { + range.y = maxHeight - bottom; + } + + break; + + default: + } + }; + + switch (action) { + // Move crop box + case ACTION_ALL: + left += range.x; + top += range.y; + break; + + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_WEST; + width = 0; + } + + break; + + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_SOUTH; + height = 0; + } + + break; + + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || aspectRatio && (top <= minTop || bottom >= maxHeight))) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += range.x / aspectRatio / 2; + } + + if (width < 0) { + action = ACTION_EAST; + width = 0; + } + + break; + + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || aspectRatio && (left <= minLeft || right >= maxWidth))) { + renderable = false; + break; + } + + check(ACTION_SOUTH); + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= range.y * aspectRatio / 2; + } + + if (height < 0) { + action = ACTION_NORTH; + height = 0; + } + + break; + + case ACTION_NORTH_EAST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + } + + break; + + case ACTION_NORTH_WEST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.y * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_WEST: + if (aspectRatio) { + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_EAST: + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + } + + break; + + // Move canvas + case ACTION_MOVE: + this.move(range.x, range.y); + renderable = false; + break; + + // Zoom canvas + case ACTION_ZOOM: + this.zoom(getMaxZoomRatio(pointers), e); + renderable = false; + break; + + // Create crop box + case ACTION_CROP: + if (!range.x || !range.y) { + renderable = false; + break; + } + + offset = getOffset(this.cropper); + left = pointer.startX - offset.left; + top = pointer.startY - offset.top; + width = cropBoxData.minWidth; + height = cropBoxData.minHeight; + + if (range.x > 0) { + action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; + } else if (range.x < 0) { + left -= width; + action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; + } + + if (range.y < 0) { + top -= height; + } + + // Show the crop box if is hidden + if (!this.cropped) { + removeClass(this.cropBox, CLASS_HIDDEN); + this.cropped = true; + + if (this.limited) { + this.limitCropBox(true, true); + } + } + + break; + + default: + } + + if (renderable) { + cropBoxData.width = width; + cropBoxData.height = height; + cropBoxData.left = left; + cropBoxData.top = top; + this.action = action; + this.renderCropBox(); + } + + // Override + each(pointers, function (p) { + p.startX = p.endX; + p.startY = p.endY; + }); + } +}; + +var methods = { + // Show the crop box manually + crop: function crop() { + if (this.ready && !this.disabled) { + if (!this.cropped) { + this.cropped = true; + this.limitCropBox(true, true); + + if (this.options.modal) { + addClass(this.dragBox, CLASS_MODAL); + } + + removeClass(this.cropBox, CLASS_HIDDEN); + } + + this.setCropBoxData(this.initialCropBoxData); + } + + return this; + }, + + + // Reset the image and crop box to their initial states + reset: function reset() { + if (this.ready && !this.disabled) { + this.imageData = extend({}, this.initialImageData); + this.canvasData = extend({}, this.initialCanvasData); + this.cropBoxData = extend({}, this.initialCropBoxData); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + } + + return this; + }, + + + // Clear the crop box + clear: function clear() { + if (this.cropped && !this.disabled) { + extend(this.cropBoxData, { + left: 0, + top: 0, + width: 0, + height: 0 + }); + + this.cropped = false; + this.renderCropBox(); + this.limitCanvas(true, true); + + // Render canvas after crop box rendered + this.renderCanvas(); + removeClass(this.dragBox, CLASS_MODAL); + addClass(this.cropBox, CLASS_HIDDEN); + } + + return this; + }, + + + /** + * Replace the image's src and rebuild the cropper + * @param {string} url - The new URL. + * @param {boolean} [onlyColorChanged] - Indicate if the new image only changed color. + * @returns {Object} this + */ + replace: function replace(url) { + var onlyColorChanged = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false; + + if (!this.disabled && url) { + if (this.isImg) { + this.element.src = url; + } + + if (onlyColorChanged) { + this.url = url; + this.image.src = url; + + if (this.ready) { + this.image2.src = url; + + each(this.previews, function (element) { + element.getElementsByTagName('img')[0].src = url; + }); + } + } else { + if (this.isImg) { + this.replaced = true; + } + + // Clear previous data + this.options.data = null; + this.load(url); + } + } + + return this; + }, + + + // Enable (unfreeze) the cropper + enable: function enable() { + if (this.ready) { + this.disabled = false; + removeClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Disable (freeze) the cropper + disable: function disable() { + if (this.ready) { + this.disabled = true; + addClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + + // Destroy the cropper and remove the instance from the image + destroy: function destroy() { + var element = this.element, + image = this.image; + + + if (this.loaded) { + if (this.isImg && this.replaced) { + element.src = this.originalUrl; + } + + this.unbuild(); + removeClass(element, CLASS_HIDDEN); + } else if (this.isImg) { + removeListener(element, EVENT_LOAD, this.onStart); + } else if (image) { + image.parentNode.removeChild(image); + } + + removeData(element, NAMESPACE); + + return this; + }, + + + /** + * Move the canvas with relative offsets + * @param {number} offsetX - The relative offset distance on the x-axis. + * @param {number} offsetY - The relative offset distance on the y-axis. + * @returns {Object} this + */ + move: function move(offsetX, offsetY) { + var _canvasData = this.canvasData, + left = _canvasData.left, + top = _canvasData.top; + + + return this.moveTo(isUndefined(offsetX) ? offsetX : left + Number(offsetX), isUndefined(offsetY) ? offsetY : top + Number(offsetY)); + }, + + + /** + * Move the canvas to an absolute point + * @param {number} x - The x-axis coordinate. + * @param {number} [y=x] - The y-axis coordinate. + * @returns {Object} this + */ + moveTo: function moveTo(x) { + var y = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : x; + var canvasData = this.canvasData; + + var changed = false; + + x = Number(x); + y = Number(y); + + if (this.ready && !this.disabled && this.options.movable) { + if (isNumber(x)) { + canvasData.left = x; + changed = true; + } + + if (isNumber(y)) { + canvasData.top = y; + changed = true; + } + + if (changed) { + this.renderCanvas(true); + } + } + + return this; + }, + + + /** + * Zoom the canvas with a relative ratio + * @param {number} ratio - The target ratio. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoom: function zoom(ratio, _originalEvent) { + var canvasData = this.canvasData; + + + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + return this.zoomTo(canvasData.width * ratio / canvasData.naturalWidth, null, _originalEvent); + }, + + + /** + * Zoom the canvas to an absolute ratio + * @param {number} ratio - The target ratio. + * @param {Object} pivot - The zoom pivot point coordinate. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoomTo: function zoomTo(ratio, pivot, _originalEvent) { + var options = this.options, + canvasData = this.canvasData; + var width = canvasData.width, + height = canvasData.height, + naturalWidth = canvasData.naturalWidth, + naturalHeight = canvasData.naturalHeight; + + + ratio = Number(ratio); + + if (ratio >= 0 && this.ready && !this.disabled && options.zoomable) { + var newWidth = naturalWidth * ratio; + var newHeight = naturalHeight * ratio; + + if (dispatchEvent(this.element, EVENT_ZOOM, { + originalEvent: _originalEvent, + oldRatio: width / naturalWidth, + ratio: newWidth / naturalWidth + }) === false) { + return this; + } + + if (_originalEvent) { + var pointers = this.pointers; + + var offset = getOffset(this.cropper); + var center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY + }; + + // Zoom from the triggering point of the event + canvasData.left -= (newWidth - width) * ((center.pageX - offset.left - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((center.pageY - offset.top - canvasData.top) / height); + } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) { + canvasData.left -= (newWidth - width) * ((pivot.x - canvasData.left) / width); + canvasData.top -= (newHeight - height) * ((pivot.y - canvasData.top) / height); + } else { + // Zoom from the center of the canvas + canvasData.left -= (newWidth - width) / 2; + canvasData.top -= (newHeight - height) / 2; + } + + canvasData.width = newWidth; + canvasData.height = newHeight; + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Rotate the canvas with a relative degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotate: function rotate(degree) { + return this.rotateTo((this.imageData.rotate || 0) + Number(degree)); + }, + + + /** + * Rotate the canvas to an absolute degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotateTo: function rotateTo(degree) { + degree = Number(degree); + + if (isNumber(degree) && this.ready && !this.disabled && this.options.rotatable) { + this.imageData.rotate = degree % 360; + this.renderCanvas(true, true); + } + + return this; + }, + + + /** + * Scale the image on the x-axis. + * @param {number} scaleX - The scale ratio on the x-axis. + * @returns {Object} this + */ + scaleX: function scaleX(_scaleX) { + var scaleY = this.imageData.scaleY; + + + return this.scale(_scaleX, isNumber(scaleY) ? scaleY : 1); + }, + + + /** + * Scale the image on the y-axis. + * @param {number} scaleY - The scale ratio on the y-axis. + * @returns {Object} this + */ + scaleY: function scaleY(_scaleY) { + var scaleX = this.imageData.scaleX; + + + return this.scale(isNumber(scaleX) ? scaleX : 1, _scaleY); + }, + + + /** + * Scale the image + * @param {number} scaleX - The scale ratio on the x-axis. + * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. + * @returns {Object} this + */ + scale: function scale(scaleX) { + var scaleY = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : scaleX; + var imageData = this.imageData; + + var transformed = false; + + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (this.ready && !this.disabled && this.options.scalable) { + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + transformed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + transformed = true; + } + + if (transformed) { + this.renderCanvas(true, true); + } + } + + return this; + }, + + + /** + * Get the cropped area position and size data (base on the original image) + * @param {boolean} [rounded=false] - Indicate if round the data values or not. + * @returns {Object} The result cropped data. + */ + getData: function getData$$1() { + var rounded = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData, + cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + x: cropBoxData.left - canvasData.left, + y: cropBoxData.top - canvasData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + + var ratio = imageData.width / imageData.naturalWidth; + + each(data, function (n, i) { + n /= ratio; + data[i] = rounded ? Math.round(n) : n; + }); + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0 + }; + } + + if (options.rotatable) { + data.rotate = imageData.rotate || 0; + } + + if (options.scalable) { + data.scaleX = imageData.scaleX || 1; + data.scaleY = imageData.scaleY || 1; + } + + return data; + }, + + + /** + * Set the cropped area position and size with new data + * @param {Object} data - The new data. + * @returns {Object} this + */ + setData: function setData$$1(data) { + var options = this.options, + imageData = this.imageData, + canvasData = this.canvasData; + + var cropBoxData = {}; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + var transformed = false; + + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== imageData.rotate) { + imageData.rotate = data.rotate; + transformed = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) { + imageData.scaleX = data.scaleX; + transformed = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) { + imageData.scaleY = data.scaleY; + transformed = true; + } + } + + if (transformed) { + this.renderCanvas(true, true); + } + + var ratio = imageData.width / imageData.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = data.x * ratio + canvasData.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = data.y * ratio + canvasData.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + this.setCropBoxData(cropBoxData); + } + + return this; + }, + + + /** + * Get the container size data. + * @returns {Object} The result container data. + */ + getContainerData: function getContainerData() { + return this.ready ? extend({}, this.containerData) : {}; + }, + + + /** + * Get the image position and size data. + * @returns {Object} The result image data. + */ + getImageData: function getImageData() { + return this.loaded ? extend({}, this.imageData) : {}; + }, + + + /** + * Get the canvas position and size data. + * @returns {Object} The result canvas data. + */ + getCanvasData: function getCanvasData() { + var canvasData = this.canvasData; + + var data = {}; + + if (this.ready) { + each(['left', 'top', 'width', 'height', 'naturalWidth', 'naturalHeight'], function (n) { + data[n] = canvasData[n]; + }); + } + + return data; + }, + + + /** + * Set the canvas position and size with new data. + * @param {Object} data - The new canvas data. + * @returns {Object} this + */ + setCanvasData: function setCanvasData(data) { + var canvasData = this.canvasData; + var aspectRatio = canvasData.aspectRatio; + + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + canvasData.left = data.left; + } + + if (isNumber(data.top)) { + canvasData.top = data.top; + } + + if (isNumber(data.width)) { + canvasData.width = data.width; + canvasData.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvasData.height = data.height; + canvasData.width = data.height * aspectRatio; + } + + this.renderCanvas(true); + } + + return this; + }, + + + /** + * Get the crop box position and size data. + * @returns {Object} The result crop box data. + */ + getCropBoxData: function getCropBoxData() { + var cropBoxData = this.cropBoxData; + + var data = void 0; + + if (this.ready && this.cropped) { + data = { + left: cropBoxData.left, + top: cropBoxData.top, + width: cropBoxData.width, + height: cropBoxData.height + }; + } + + return data || {}; + }, + + + /** + * Set the crop box position and size with new data. + * @param {Object} data - The new crop box data. + * @returns {Object} this + */ + setCropBoxData: function setCropBoxData(data) { + var cropBoxData = this.cropBoxData; + var aspectRatio = this.options.aspectRatio; + + var widthChanged = void 0; + var heightChanged = void 0; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + cropBoxData.left = data.left; + } + + if (isNumber(data.top)) { + cropBoxData.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBoxData.width) { + widthChanged = true; + cropBoxData.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBoxData.height) { + heightChanged = true; + cropBoxData.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else if (heightChanged) { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.renderCropBox(); + } + + return this; + }, + + + /** + * Get a canvas drawn the cropped image. + * @param {Object} [options={}] - The config options. + * @returns {HTMLCanvasElement} - The result canvas. + */ + getCroppedCanvas: function getCroppedCanvas() { + var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; + + if (!this.ready || !window.HTMLCanvasElement) { + return null; + } + + var canvasData = this.canvasData; + + var source = getSourceCanvas(this.image, this.imageData, canvasData, options); + + // Returns the source canvas if it is not cropped. + if (!this.cropped) { + return source; + } + + var _getData = this.getData(), + x = _getData.x, + y = _getData.y, + initialWidth = _getData.width, + initialHeight = _getData.height; + + var aspectRatio = initialWidth / initialHeight; + var maxSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.maxWidth || Infinity, + height: options.maxHeight || Infinity + }); + var minSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.minWidth || 0, + height: options.minHeight || 0 + }); + + var _getContainSizes = getContainSizes({ + aspectRatio: aspectRatio, + width: options.width || initialWidth, + height: options.height || initialHeight + }), + width = _getContainSizes.width, + height = _getContainSizes.height; + + width = Math.min(maxSizes.width, Math.max(minSizes.width, width)); + height = Math.min(maxSizes.height, Math.max(minSizes.height, height)); + + var canvas = document.createElement('canvas'); + var context = canvas.getContext('2d'); + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + + context.fillStyle = options.fillColor || 'transparent'; + context.fillRect(0, 0, width, height); + + var _options$imageSmoothi = options.imageSmoothingEnabled, + imageSmoothingEnabled = _options$imageSmoothi === undefined ? true : _options$imageSmoothi, + imageSmoothingQuality = options.imageSmoothingQuality; + + + context.imageSmoothingEnabled = imageSmoothingEnabled; + + if (imageSmoothingQuality) { + context.imageSmoothingQuality = imageSmoothingQuality; + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + var sourceWidth = source.width; + var sourceHeight = source.height; + + // Source canvas parameters + var srcX = x; + var srcY = y; + var srcWidth = void 0; + var srcHeight = void 0; + + // Destination canvas parameters + var dstX = void 0; + var dstY = void 0; + var dstWidth = void 0; + var dstHeight = void 0; + + if (srcX <= -initialWidth || srcX > sourceWidth) { + srcX = 0; + srcWidth = 0; + dstX = 0; + dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = Math.min(sourceWidth, initialWidth + srcX); + dstWidth = srcWidth; + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = Math.min(initialWidth, sourceWidth - srcX); + dstWidth = srcWidth; + } + + if (srcWidth <= 0 || srcY <= -initialHeight || srcY > sourceHeight) { + srcY = 0; + srcHeight = 0; + dstY = 0; + dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = Math.min(sourceHeight, initialHeight + srcY); + dstHeight = srcHeight; + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = Math.min(initialHeight, sourceHeight - srcY); + dstHeight = srcHeight; + } + + // All the numerical parameters should be integer for `drawImage` + // https://github.com/fengyuanchen/cropper/issues/476 + var params = [srcX, srcY, srcWidth, srcHeight]; + + // Avoid "IndexSizeError" + if (dstWidth > 0 && dstHeight > 0) { + var scale = width / initialWidth; + + params.push(dstX * scale, dstY * scale, dstWidth * scale, dstHeight * scale); + } + + context.drawImage.apply(context, [source].concat(toConsumableArray(params.map(function (param) { + return Math.floor(normalizeDecimalNumber(param)); + })))); + + return canvas; + }, + + + /** + * Change the aspect ratio of the crop box. + * @param {number} aspectRatio - The new aspect ratio. + * @returns {Object} this + */ + setAspectRatio: function setAspectRatio(aspectRatio) { + var options = this.options; + + + if (!this.disabled && !isUndefined(aspectRatio)) { + // 0 -> NaN + options.aspectRatio = Math.max(0, aspectRatio) || NaN; + + if (this.ready) { + this.initCropBox(); + + if (this.cropped) { + this.renderCropBox(); + } + } + } + + return this; + }, + + + /** + * Change the drag mode. + * @param {string} mode - The new drag mode. + * @returns {Object} this + */ + setDragMode: function setDragMode(mode) { + var options = this.options, + dragBox = this.dragBox, + face = this.face; + + + if (this.loaded && !this.disabled) { + var croppable = mode === DRAG_MODE_CROP; + var movable = options.movable && mode === DRAG_MODE_MOVE; + + mode = croppable || movable ? mode : DRAG_MODE_NONE; + + setData(dragBox, DATA_ACTION, mode); + toggleClass(dragBox, CLASS_CROP, croppable); + toggleClass(dragBox, CLASS_MOVE, movable); + + if (!options.cropBoxMovable) { + // Sync drag mode to crop box when it is not movable + setData(face, DATA_ACTION, mode); + toggleClass(face, CLASS_CROP, croppable); + toggleClass(face, CLASS_MOVE, movable); + } + } + + return this; + } +}; + +var AnotherCropper = WINDOW.Cropper; + +var Cropper = function () { + /** + * Create a new Cropper. + * @param {Element} element - The target element for cropping. + * @param {Object} [options={}] - The configuration options. + */ + function Cropper(element) { + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + classCallCheck(this, Cropper); + + if (!element || !REGEXP_TAG_NAME.test(element.tagName)) { + throw new Error('The first argument is required and must be an or element.'); + } + + this.element = element; + this.options = extend({}, DEFAULTS, isPlainObject(options) && options); + this.complete = false; + this.cropped = false; + this.disabled = false; + this.isImg = false; + this.limited = false; + this.loaded = false; + this.ready = false; + this.replaced = false; + this.wheeling = false; + this.originalUrl = ''; + this.canvasData = null; + this.cropBoxData = null; + this.previews = null; + this.pointers = {}; + this.init(); + } + + createClass(Cropper, [{ + key: 'init', + value: function init() { + var element = this.element; + + var tagName = element.tagName.toLowerCase(); + var url = void 0; + + if (getData(element, NAMESPACE)) { + return; + } + + setData(element, NAMESPACE, this); + + if (tagName === 'img') { + this.isImg = true; + + // e.g.: "img/picture.jpg" + url = element.getAttribute('src') || ''; + this.originalUrl = url; + + // Stop when it's a blank image + if (!url) { + return; + } + + // e.g.: "http://example.com/img/picture.jpg" + url = element.src; + } else if (tagName === 'canvas' && window.HTMLCanvasElement) { + url = element.toDataURL(); + } + + this.load(url); + } + }, { + key: 'load', + value: function load(url) { + var _this = this; + + if (!url) { + return; + } + + this.url = url; + this.imageData = {}; + + var element = this.element, + options = this.options; + + + if (!options.checkOrientation || !window.ArrayBuffer) { + this.clone(); + return; + } + + // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari + if (REGEXP_DATA_URL.test(url)) { + if (REGEXP_DATA_URL_JPEG.test(url)) { + this.read(dataURLToArrayBuffer(url)); + } else { + this.clone(); + } + + return; + } + + var xhr = new XMLHttpRequest(); + + xhr.onerror = function () { + _this.clone(); + }; + + xhr.onload = function () { + _this.read(xhr.response); + }; + + if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) { + url = addTimestamp(url); + } + + xhr.open('get', url); + xhr.responseType = 'arraybuffer'; + xhr.withCredentials = element.crossOrigin === 'use-credentials'; + xhr.send(); + } + }, { + key: 'read', + value: function read(arrayBuffer) { + var options = this.options, + imageData = this.imageData; + + var orientation = getOrientation(arrayBuffer); + var rotate = 0; + var scaleX = 1; + var scaleY = 1; + + if (orientation > 1) { + this.url = arrayBufferToDataURL(arrayBuffer, 'image/jpeg'); + + var _parseOrientation = parseOrientation(orientation); + + rotate = _parseOrientation.rotate; + scaleX = _parseOrientation.scaleX; + scaleY = _parseOrientation.scaleY; + } + + if (options.rotatable) { + imageData.rotate = rotate; + } + + if (options.scalable) { + imageData.scaleX = scaleX; + imageData.scaleY = scaleY; + } + + this.clone(); + } + }, { + key: 'clone', + value: function clone() { + var element = this.element, + url = this.url; + + var crossOrigin = void 0; + var crossOriginUrl = void 0; + + if (this.options.checkCrossOrigin && isCrossOriginURL(url)) { + crossOrigin = element.crossOrigin; + + + if (crossOrigin) { + crossOriginUrl = url; + } else { + crossOrigin = 'anonymous'; + + // Bust cache when there is not a "crossOrigin" property + crossOriginUrl = addTimestamp(url); + } + } + + this.crossOrigin = crossOrigin; + this.crossOriginUrl = crossOriginUrl; + + var image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = crossOriginUrl || url; + + var start = proxy(this.start, this); + var stop = proxy(this.stop, this); + + this.image = image; + this.onStart = start; + this.onStop = stop; + + if (this.isImg) { + if (element.complete) { + this.start(); + } else { + addListener(element, EVENT_LOAD, start); + } + } else { + addListener(image, EVENT_LOAD, start); + addListener(image, EVENT_ERROR, stop); + addClass(image, CLASS_HIDE); + element.parentNode.insertBefore(image, element.nextSibling); + } + } + }, { + key: 'start', + value: function start(event) { + var _this2 = this; + + var image = this.isImg ? this.element : this.image; + + if (event) { + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + } + + getImageNaturalSizes(image, function (naturalWidth, naturalHeight) { + extend(_this2.imageData, { + naturalWidth: naturalWidth, + naturalHeight: naturalHeight, + aspectRatio: naturalWidth / naturalHeight + }); + _this2.loaded = true; + _this2.build(); + }); + } + }, { + key: 'stop', + value: function stop() { + var image = this.image; + + + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + image.parentNode.removeChild(image); + this.image = null; + } + }, { + key: 'build', + value: function build() { + var _this3 = this; + + if (!this.loaded) { + return; + } + + // Unbuild first when replace + if (this.ready) { + this.unbuild(); + } + + var element = this.element, + options = this.options, + image = this.image; + + // Create cropper elements + + var container = element.parentNode; + var template = document.createElement('div'); + + template.innerHTML = TEMPLATE; + + var cropper = template.querySelector('.' + NAMESPACE + '-container'); + var canvas = cropper.querySelector('.' + NAMESPACE + '-canvas'); + var dragBox = cropper.querySelector('.' + NAMESPACE + '-drag-box'); + var cropBox = cropper.querySelector('.' + NAMESPACE + '-crop-box'); + var face = cropBox.querySelector('.' + NAMESPACE + '-face'); + + this.container = container; + this.cropper = cropper; + this.canvas = canvas; + this.dragBox = dragBox; + this.cropBox = cropBox; + this.viewBox = cropper.querySelector('.' + NAMESPACE + '-view-box'); + this.face = face; + + canvas.appendChild(image); + + // Hide the original image + addClass(element, CLASS_HIDDEN); + + // Inserts the cropper after to the current image + container.insertBefore(cropper, element.nextSibling); + + // Show the image if is hidden + if (!this.isImg) { + removeClass(image, CLASS_HIDE); + } + + this.initPreview(); + this.bind(); + + options.aspectRatio = Math.max(0, options.aspectRatio) || NaN; + options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0; + + this.cropped = options.autoCrop; + + if (options.autoCrop) { + if (options.modal) { + addClass(dragBox, CLASS_MODAL); + } + } else { + addClass(cropBox, CLASS_HIDDEN); + } + + if (!options.guides) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-dashed'), CLASS_HIDDEN); + } + + if (!options.center) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-center'), CLASS_HIDDEN); + } + + if (options.background) { + addClass(cropper, NAMESPACE + '-bg'); + } + + if (!options.highlight) { + addClass(face, CLASS_INVISIBLE); + } + + if (options.cropBoxMovable) { + addClass(face, CLASS_MOVE); + setData(face, DATA_ACTION, ACTION_ALL); + } + + if (!options.cropBoxResizable) { + addClass(cropBox.getElementsByClassName(NAMESPACE + '-line'), CLASS_HIDDEN); + addClass(cropBox.getElementsByClassName(NAMESPACE + '-point'), CLASS_HIDDEN); + } + + this.setDragMode(options.dragMode); + this.render(); + this.ready = true; + this.setData(options.data); + + // Call the "ready" option asynchronously to keep "image.cropper" is defined + this.completing = setTimeout(function () { + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, { + once: true + }); + } + + dispatchEvent(element, EVENT_READY); + dispatchEvent(element, EVENT_CROP, _this3.getData()); + + _this3.complete = true; + }, 0); + } + }, { + key: 'unbuild', + value: function unbuild() { + if (!this.ready) { + return; + } + + if (!this.complete) { + clearTimeout(this.completing); + } + + this.ready = false; + this.complete = false; + this.initialImageData = null; + + // Clear `initialCanvasData` is necessary when replace + this.initialCanvasData = null; + this.initialCropBoxData = null; + this.containerData = null; + this.canvasData = null; + + // Clear `cropBoxData` is necessary when replace + this.cropBoxData = null; + this.unbind(); + this.resetPreview(); + this.previews = null; + this.viewBox = null; + this.cropBox = null; + this.dragBox = null; + this.canvas = null; + this.container = null; + this.cropper.parentNode.removeChild(this.cropper); + this.cropper = null; + } + + /** + * Get the no conflict cropper class. + * @returns {Cropper} The cropper class. + */ + + }], [{ + key: 'noConflict', + value: function noConflict() { + window.Cropper = AnotherCropper; + return Cropper; + } + + /** + * Change the default options. + * @param {Object} options - The new default options. + */ + + }, { + key: 'setDefaults', + value: function setDefaults(options) { + extend(DEFAULTS, isPlainObject(options) && options); + } + }]); + return Cropper; +}(); + +extend(Cropper.prototype, render, preview, events, handlers, change, methods); + +return Cropper; + +}))); diff --git a/library/cropperjs/docs/js/main.js b/library/cropperjs/docs/js/main.js new file mode 100644 index 000000000..d74afbd60 --- /dev/null +++ b/library/cropperjs/docs/js/main.js @@ -0,0 +1,298 @@ +window.onload = function () { + + 'use strict'; + + var Cropper = window.Cropper; + var URL = window.URL || window.webkitURL; + var container = document.querySelector('.img-container'); + var image = container.getElementsByTagName('img').item(0); + var download = document.getElementById('download'); + var actions = document.getElementById('actions'); + var dataX = document.getElementById('dataX'); + var dataY = document.getElementById('dataY'); + var dataHeight = document.getElementById('dataHeight'); + var dataWidth = document.getElementById('dataWidth'); + var dataRotate = document.getElementById('dataRotate'); + var dataScaleX = document.getElementById('dataScaleX'); + var dataScaleY = document.getElementById('dataScaleY'); + var options = { + aspectRatio: 16 / 9, + preview: '.img-preview', + ready: function (e) { + console.log(e.type); + }, + cropstart: function (e) { + console.log(e.type, e.detail.action); + }, + cropmove: function (e) { + console.log(e.type, e.detail.action); + }, + cropend: function (e) { + console.log(e.type, e.detail.action); + }, + crop: function (e) { + var data = e.detail; + + console.log(e.type); + dataX.value = Math.round(data.x); + dataY.value = Math.round(data.y); + dataHeight.value = Math.round(data.height); + dataWidth.value = Math.round(data.width); + dataRotate.value = typeof data.rotate !== 'undefined' ? data.rotate : ''; + dataScaleX.value = typeof data.scaleX !== 'undefined' ? data.scaleX : ''; + dataScaleY.value = typeof data.scaleY !== 'undefined' ? data.scaleY : ''; + }, + zoom: function (e) { + console.log(e.type, e.detail.ratio); + } + }; + var cropper = new Cropper(image, options); + var originalImageURL = image.src; + var uploadedImageType = 'image/jpeg'; + var uploadedImageURL; + + // Tooltip + $('[data-toggle="tooltip"]').tooltip(); + + // Buttons + if (!document.createElement('canvas').getContext) { + $('button[data-method="getCroppedCanvas"]').prop('disabled', true); + } + + if (typeof document.createElement('cropper').style.transition === 'undefined') { + $('button[data-method="rotate"]').prop('disabled', true); + $('button[data-method="scale"]').prop('disabled', true); + } + + // Download + if (typeof download.download === 'undefined') { + download.className += ' disabled'; + } + + // Options + actions.querySelector('.docs-toggles').onchange = function (event) { + var e = event || window.event; + var target = e.target || e.srcElement; + var cropBoxData; + var canvasData; + var isCheckbox; + var isRadio; + + if (!cropper) { + return; + } + + if (target.tagName.toLowerCase() === 'label') { + target = target.querySelector('input'); + } + + isCheckbox = target.type === 'checkbox'; + isRadio = target.type === 'radio'; + + if (isCheckbox || isRadio) { + if (isCheckbox) { + options[target.name] = target.checked; + cropBoxData = cropper.getCropBoxData(); + canvasData = cropper.getCanvasData(); + + options.ready = function () { + console.log('ready'); + cropper.setCropBoxData(cropBoxData).setCanvasData(canvasData); + }; + } else { + options[target.name] = target.value; + options.ready = function () { + console.log('ready'); + }; + } + + // Restart + cropper.destroy(); + cropper = new Cropper(image, options); + } + }; + + // Methods + actions.querySelector('.docs-buttons').onclick = function (event) { + var e = event || window.event; + var target = e.target || e.srcElement; + var cropped; + var result; + var input; + var data; + + if (!cropper) { + return; + } + + while (target !== this) { + if (target.getAttribute('data-method')) { + break; + } + + target = target.parentNode; + } + + if (target === this || target.disabled || target.className.indexOf('disabled') > -1) { + return; + } + + data = { + method: target.getAttribute('data-method'), + target: target.getAttribute('data-target'), + option: target.getAttribute('data-option') || undefined, + secondOption: target.getAttribute('data-second-option') || undefined + }; + + cropped = cropper.cropped; + + if (data.method) { + if (typeof data.target !== 'undefined') { + input = document.querySelector(data.target); + + if (!target.hasAttribute('data-option') && data.target && input) { + try { + data.option = JSON.parse(input.value); + } catch (e) { + console.log(e.message); + } + } + } + + switch (data.method) { + case 'rotate': + if (cropped && options.viewMode > 0) { + cropper.clear(); + } + + break; + + case 'getCroppedCanvas': + try { + data.option = JSON.parse(data.option); + } catch (e) { + console.log(e.message); + } + + if (uploadedImageType === 'image/jpeg') { + if (!data.option) { + data.option = {}; + } + + data.option.fillColor = '#fff'; + } + + break; + } + + result = cropper[data.method](data.option, data.secondOption); + + switch (data.method) { + case 'rotate': + if (cropped && options.viewMode > 0) { + cropper.crop(); + } + + break; + + case 'scaleX': + case 'scaleY': + target.setAttribute('data-option', -data.option); + break; + + case 'getCroppedCanvas': + if (result) { + // Bootstrap's Modal + $('#getCroppedCanvasModal').modal().find('.modal-body').html(result); + + if (!download.disabled) { + download.href = result.toDataURL(uploadedImageType); + } + } + + break; + + case 'destroy': + cropper = null; + + if (uploadedImageURL) { + URL.revokeObjectURL(uploadedImageURL); + uploadedImageURL = ''; + image.src = originalImageURL; + } + + break; + } + + if (typeof result === 'object' && result !== cropper && input) { + try { + input.value = JSON.stringify(result); + } catch (e) { + console.log(e.message); + } + } + } + }; + + document.body.onkeydown = function (event) { + var e = event || window.event; + + if (!cropper || this.scrollTop > 300) { + return; + } + + switch (e.keyCode) { + case 37: + e.preventDefault(); + cropper.move(-1, 0); + break; + + case 38: + e.preventDefault(); + cropper.move(0, -1); + break; + + case 39: + e.preventDefault(); + cropper.move(1, 0); + break; + + case 40: + e.preventDefault(); + cropper.move(0, 1); + break; + } + }; + + // Import image + var inputImage = document.getElementById('inputImage'); + + if (URL) { + inputImage.onchange = function () { + var files = this.files; + var file; + + if (cropper && files && files.length) { + file = files[0]; + + if (/^image\/\w+/.test(file.type)) { + uploadedImageType = file.type; + + if (uploadedImageURL) { + URL.revokeObjectURL(uploadedImageURL); + } + + image.src = uploadedImageURL = URL.createObjectURL(file); + cropper.destroy(); + cropper = new Cropper(image, options); + inputImage.value = null; + } else { + window.alert('Please choose an image file.'); + } + } + }; + } else { + inputImage.disabled = true; + inputImage.parentNode.className += ' disabled'; + } +}; diff --git a/library/cropperjs/examples/a-range-of-aspect-ratio.html b/library/cropperjs/examples/a-range-of-aspect-ratio.html new file mode 100644 index 000000000..fae5cb60b --- /dev/null +++ b/library/cropperjs/examples/a-range-of-aspect-ratio.html @@ -0,0 +1,71 @@ + + + + + + + Cropper.js + + + + + +
    +

    Cropper with a range of aspect ratio

    +
    + Picture +
    +
    + + + + + diff --git a/library/cropperjs/examples/crop-a-round-image.html b/library/cropperjs/examples/crop-a-round-image.html new file mode 100644 index 000000000..da027d847 --- /dev/null +++ b/library/cropperjs/examples/crop-a-round-image.html @@ -0,0 +1,103 @@ + + + + + + + Cropper.js + + + + + +
    +

    Crop a round image

    +

    Image

    +
    + Picture +
    +

    Result

    +

    + +

    +
    +
    + + + + + diff --git a/library/cropperjs/examples/crop-cross-origin-image.html b/library/cropperjs/examples/crop-cross-origin-image.html new file mode 100644 index 000000000..54f08664a --- /dev/null +++ b/library/cropperjs/examples/crop-cross-origin-image.html @@ -0,0 +1,49 @@ + + + + + + + Cropper.js + + + + + +
    +

    Crop a cross origin image

    +

    A cross origin image with a crossorigin attribute and an available Access-Control-Allow-Origin response header can be cropped by Cropper.

    +

    Image

    +
    + +
    +

    Result

    +
    +
    + + + + + diff --git a/library/cropperjs/examples/crop-on-canvas.html b/library/cropperjs/examples/crop-on-canvas.html new file mode 100644 index 000000000..228e36f75 --- /dev/null +++ b/library/cropperjs/examples/crop-on-canvas.html @@ -0,0 +1,64 @@ + + + + + + + Cropper.js + + + + + +
    +

    Crop on canvas with Cropper

    +

    Image

    +
    + Picture +
    +

    Canvas

    +
    + +
    +
    + + + + + diff --git a/library/cropperjs/examples/cropper-in-modal.html b/library/cropperjs/examples/cropper-in-modal.html new file mode 100644 index 000000000..a9ce3e80b --- /dev/null +++ b/library/cropperjs/examples/cropper-in-modal.html @@ -0,0 +1,76 @@ + + + + + + + Cropper.js + + + + + + +
    +

    Cropper in a Bootstrap modal

    + + + + + + +
    + + + + + + + diff --git a/library/cropperjs/examples/customize-preview.html b/library/cropperjs/examples/customize-preview.html new file mode 100644 index 000000000..ea1c24b88 --- /dev/null +++ b/library/cropperjs/examples/customize-preview.html @@ -0,0 +1,123 @@ + + + + + + + Cropper.js + + + + + +
    +

    Customize preview for Cropper

    +
    +
    + Picture +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + + + + + diff --git a/library/cropperjs/examples/fixed-crop-box.html b/library/cropperjs/examples/fixed-crop-box.html new file mode 100644 index 000000000..b9f1101fb --- /dev/null +++ b/library/cropperjs/examples/fixed-crop-box.html @@ -0,0 +1,48 @@ + + + + + + + Cropper.js + + + + + +
    +

    Cropper with fixed crop box

    +
    + Picture +
    +
    + + + + + diff --git a/library/cropperjs/examples/full-crop-box.html b/library/cropperjs/examples/full-crop-box.html new file mode 100644 index 000000000..7065eab94 --- /dev/null +++ b/library/cropperjs/examples/full-crop-box.html @@ -0,0 +1,48 @@ + + + + + + + Cropper.js + + + + + +
    +

    Cropper with full crop box

    +
    + Picture +
    +
    + + + + + diff --git a/library/cropperjs/examples/mask-an-image.html b/library/cropperjs/examples/mask-an-image.html new file mode 100644 index 000000000..d821da43b --- /dev/null +++ b/library/cropperjs/examples/mask-an-image.html @@ -0,0 +1,123 @@ + + + + + + + + Cropper.js + + + + + + +
    +

    Mask an image (Redaction)

    +

    Image

    +
    + Picture +
    +

    Result

    +

    +
    +
    + + + + + + diff --git a/library/cropperjs/examples/multiple-croppers.html b/library/cropperjs/examples/multiple-croppers.html new file mode 100644 index 000000000..6b12e70b2 --- /dev/null +++ b/library/cropperjs/examples/multiple-croppers.html @@ -0,0 +1,48 @@ + + + + + + + Cropper.js + + + + + +
    +

    Multiple Croppers

    +

    Cropper

    +
    + Picture +
    +

    Another

    +
    + Picture +
    +
    + + + + + diff --git a/library/cropperjs/examples/responsive-container.html b/library/cropperjs/examples/responsive-container.html new file mode 100644 index 000000000..c1aa7483b --- /dev/null +++ b/library/cropperjs/examples/responsive-container.html @@ -0,0 +1,49 @@ + + + + + + + Cropper.js + + + + + +
    +

    Cropper with responsive container

    +

    + +

    +
    + Picture +
    +
    + + + + + diff --git a/library/cropperjs/package-lock.json b/library/cropperjs/package-lock.json new file mode 100644 index 000000000..229ee70fa --- /dev/null +++ b/library/cropperjs/package-lock.json @@ -0,0 +1,9111 @@ +{ + "name": "cropperjs", + "version": "1.2.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "JSONStream": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-0.8.4.tgz", + "integrity": "sha1-kWV9/m/4V0gwZhMrRhi2Lo9Ih70=", + "dev": true, + "requires": { + "jsonparse": "0.0.5", + "through": "2.3.8" + } + }, + "acorn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.3.0.tgz", + "integrity": "sha512-Yej+zOJ1Dm/IMZzzj78OntP/r3zHEaKcyNoU2lAaxPtrseM6rF0xwqoz5Q5ysAiED9hTjI2hgtvLXitlCN1/Ug==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz", + "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "json-schema-traverse": "0.3.1", + "json-stable-stringify": "1.0.1" + } + }, + "ajv-keywords": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.0.tgz", + "integrity": "sha1-opbhf3v658HOT34N5T0pyzIWLfA=", + "dev": true + }, + "alphanum-sort": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", + "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "requires": { + "string-width": "2.1.1" + } + }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", + "dev": true + }, + "array-filter": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", + "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-map": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", + "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", + "dev": true + }, + "array-reduce": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", + "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "autoprefixer": { + "version": "6.7.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", + "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000744", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000744", + "electron-to-chromium": "1.3.24" + } + } + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.0", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.7", + "slash": "1.0.0", + "source-map": "0.5.7" + } + }, + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + } + }, + "babel-helper-builder-binary-assignment-operator-visitor": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz", + "integrity": "sha1-zORReto1b0IgvK6KAsKzRvmlZmQ=", + "dev": true, + "requires": { + "babel-helper-explode-assignable-expression": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-explode-assignable-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz", + "integrity": "sha1-8luCz33BBDPFX3BZLVdGQArCLKo=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-remap-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz", + "integrity": "sha1-XsWBgnrXI/7N04HxySg5BnbkVRs=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-external-helpers": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-external-helpers/-/babel-plugin-external-helpers-6.22.0.tgz", + "integrity": "sha1-IoX0iwK9Xe3oUXXK+MYuhq3M76E=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-syntax-async-functions": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz", + "integrity": "sha1-ytnK0RkbWtY0vzCuCHI5HgZHvpU=", + "dev": true + }, + "babel-plugin-syntax-exponentiation-operator": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz", + "integrity": "sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4=", + "dev": true + }, + "babel-plugin-syntax-trailing-function-commas": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz", + "integrity": "sha1-ugNgk3+NBuQBgKQ/4NVhb/9TLPM=", + "dev": true + }, + "babel-plugin-transform-async-to-generator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz", + "integrity": "sha1-ZTbjeK/2yx1VF6wOQOs+n8jQh2E=", + "dev": true, + "requires": { + "babel-helper-remap-async-to-generator": "6.24.1", + "babel-plugin-syntax-async-functions": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-exponentiation-operator": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz", + "integrity": "sha1-KrDJx/MJj6SJB3cruBP+QejeOg4=", + "dev": true, + "requires": { + "babel-helper-builder-binary-assignment-operator-visitor": "6.24.1", + "babel-plugin-syntax-exponentiation-operator": "6.13.0", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-preset-env": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/babel-preset-env/-/babel-preset-env-1.6.1.tgz", + "integrity": "sha512-W6VIyA6Ch9ePMI7VptNn2wBM6dbG0eSz25HEiL40nQXCsXGTGZSTZu1Iap+cj3Q0S5a7T9+529l/5Bkvd+afNA==", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-syntax-trailing-function-commas": "6.22.0", + "babel-plugin-transform-async-to-generator": "6.24.1", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-exponentiation-operator": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0", + "browserslist": "2.5.0", + "invariant": "2.2.2", + "semver": "5.4.1" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "binary-extensions": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", + "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=", + "dev": true + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "boxen": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.2.2.tgz", + "integrity": "sha1-Px1AMsMP/qnUsCwyLq8up0HcvOU=", + "dev": true, + "requires": { + "ansi-align": "2.0.0", + "camelcase": "4.1.0", + "chalk": "2.3.0", + "cli-boxes": "1.0.0", + "string-width": "2.1.1", + "term-size": "1.2.0", + "widest-line": "1.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "browserslist": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-2.5.0.tgz", + "integrity": "sha512-6Vw1LIigGw8zCK0gxczksUMZlO+oPUwBazAztMmFL/F8D5wB0qCuxRJGYgYM3JzaO0v2ZMRIg+nnnOgNsPGHeA==", + "dev": true, + "requires": { + "caniuse-lite": "1.0.30000744", + "electron-to-chromium": "1.3.24" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "caniuse-api": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", + "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000744", + "lodash.memoize": "4.1.2", + "lodash.uniq": "4.5.0" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000744", + "electron-to-chromium": "1.3.24" + } + } + } + }, + "caniuse-db": { + "version": "1.0.30000744", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000744.tgz", + "integrity": "sha1-AHWP991fcTjTShVgjcz3Glllb/4=", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30000744", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000744.tgz", + "integrity": "sha1-hg+lyDujT+YZOX1gfzC7R0ghZxs=", + "dev": true + }, + "capture-stack-trace": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz", + "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "clap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", + "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "dev": true, + "requires": { + "chalk": "1.1.3" + } + }, + "cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-spinners": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.1.0.tgz", + "integrity": "sha1-8YR7FohE2RemceudFH499JfJDQY=", + "dev": true + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "clone": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", + "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=", + "dev": true + }, + "clone-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-regexp/-/clone-regexp-1.0.0.tgz", + "integrity": "sha1-6uCiQT9VwJQvgYwin+/OhF1/Oxw=", + "dev": true, + "requires": { + "is-regexp": "1.0.0", + "is-supported-regexp-flag": "1.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "coa": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", + "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", + "dev": true, + "requires": { + "q": "1.5.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "color": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", + "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", + "dev": true, + "requires": { + "clone": "1.0.2", + "color-convert": "1.9.0", + "color-string": "0.3.0" + } + }, + "color-convert": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", + "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-diff": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/color-diff/-/color-diff-0.1.7.tgz", + "integrity": "sha1-bbeM2UgqjkWdQIIer0tQMoPcuOI=", + "dev": true + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-string": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", + "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "colorguard": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/colorguard/-/colorguard-1.2.0.tgz", + "integrity": "sha1-8/rK9cquuk71RlPZ+yW7cxd8DYQ=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "color-diff": "0.1.7", + "log-symbols": "1.0.2", + "object-assign": "4.1.1", + "pipetteur": "2.0.3", + "plur": "2.1.2", + "postcss": "5.2.18", + "postcss-reporter": "1.4.1", + "text-table": "0.2.0", + "yargs": "1.3.3" + }, + "dependencies": { + "postcss-reporter": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-1.4.1.tgz", + "integrity": "sha1-wTbwpbFhkV83ndN2XGEHX357mvI=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.4", + "log-symbols": "1.0.2", + "postcss": "5.2.18" + } + }, + "yargs": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-1.3.3.tgz", + "integrity": "sha1-BU3oth8i7v23IHBZ6u+da4P7kxo=", + "dev": true + } + } + }, + "colormin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", + "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", + "dev": true, + "requires": { + "color": "0.11.4", + "css-color-names": "0.0.4", + "has": "1.0.1" + } + }, + "colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", + "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "configstore": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.1.tgz", + "integrity": "sha512-5oNkD/L++l0O6xGXxb1EWS7SivtjfGQlRyxJsYgE0Z495/L81e2h4/d3r969hoPXuFItzNOKMtsXgYG4c7dYvw==", + "dev": true, + "requires": { + "dot-prop": "4.2.0", + "graceful-fs": "4.1.11", + "make-dir": "1.1.0", + "unique-string": "1.0.0", + "write-file-atomic": "2.3.0", + "xdg-basedir": "3.0.0" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", + "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=", + "dev": true + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cosmiconfig": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", + "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "dev": true, + "requires": { + "is-directory": "0.3.1", + "js-yaml": "3.7.0", + "minimist": "1.2.0", + "object-assign": "4.1.1", + "os-homedir": "1.0.2", + "parse-json": "2.2.0", + "require-from-string": "1.2.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "cp-file": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-3.2.0.tgz", + "integrity": "sha1-b4NhYlRiTwrViqSqjQdvAmvn4Yg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1", + "nested-error-stacks": "1.0.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "readable-stream": "2.3.3" + } + }, + "cpy": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-4.0.1.tgz", + "integrity": "sha1-tnJn66LzlgugalphrJQDNCKDNCQ=", + "dev": true, + "requires": { + "cp-file": "3.2.0", + "globby": "4.1.0", + "meow": "3.7.0", + "nested-error-stacks": "1.0.2", + "object-assign": "4.1.1", + "pinkie-promise": "2.0.1" + } + }, + "cpy-cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cpy-cli/-/cpy-cli-1.0.1.tgz", + "integrity": "sha1-Z/taSi3sKMqKv/N13kuecfanVhw=", + "dev": true, + "requires": { + "cpy": "4.0.1", + "meow": "3.7.0" + } + }, + "create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "requires": { + "capture-stack-trace": "1.0.0" + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, + "requires": { + "boom": "5.2.0" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + } + } + }, + "crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true + }, + "css-color-function": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/css-color-function/-/css-color-function-1.3.3.tgz", + "integrity": "sha1-jtJMLAIFBzM5+voAS8jBQfzLKC4=", + "dev": true, + "requires": { + "balanced-match": "0.1.0", + "color": "0.11.4", + "debug": "3.1.0", + "rgb": "0.1.0" + }, + "dependencies": { + "balanced-match": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.1.0.tgz", + "integrity": "sha1-tQS9BYabOSWd0MXvw12EMXbczEo=", + "dev": true + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "css-color-list": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-color-list/-/css-color-list-0.0.1.tgz", + "integrity": "sha1-hxjoaVrnosyHh76HFfHACKfyixU=", + "dev": true, + "requires": { + "css-color-names": "0.0.1" + }, + "dependencies": { + "css-color-names": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.1.tgz", + "integrity": "sha1-XQVI+iVkVu3kqaDCrHqxnT6xrYE=", + "dev": true + } + } + }, + "css-color-names": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", + "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=", + "dev": true + }, + "css-rule-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/css-rule-stream/-/css-rule-stream-1.1.0.tgz", + "integrity": "sha1-N4bnGYmD2WWibjGVfgkHjLt3BaI=", + "dev": true, + "requires": { + "css-tokenize": "1.0.1", + "duplexer2": "0.0.2", + "ldjson-stream": "1.2.1", + "through2": "0.6.5" + } + }, + "css-tokenize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-tokenize/-/css-tokenize-1.0.1.tgz", + "integrity": "sha1-RiXLHtohwUOFi3+B1oA8HSb8FL4=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "1.1.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "css-unit-converter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.1.tgz", + "integrity": "sha1-2bkoGtz9jO2TW9urqDeGiX9k6ZY=", + "dev": true + }, + "cssnano": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", + "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", + "dev": true, + "requires": { + "autoprefixer": "6.7.7", + "decamelize": "1.2.0", + "defined": "1.0.0", + "has": "1.0.1", + "object-assign": "4.1.1", + "postcss": "5.2.18", + "postcss-calc": "5.3.1", + "postcss-colormin": "2.2.2", + "postcss-convert-values": "2.6.1", + "postcss-discard-comments": "2.0.4", + "postcss-discard-duplicates": "2.1.0", + "postcss-discard-empty": "2.1.0", + "postcss-discard-overridden": "0.1.1", + "postcss-discard-unused": "2.2.3", + "postcss-filter-plugins": "2.0.2", + "postcss-merge-idents": "2.1.7", + "postcss-merge-longhand": "2.0.2", + "postcss-merge-rules": "2.1.2", + "postcss-minify-font-values": "1.0.5", + "postcss-minify-gradients": "1.0.5", + "postcss-minify-params": "1.2.2", + "postcss-minify-selectors": "2.1.1", + "postcss-normalize-charset": "1.1.1", + "postcss-normalize-url": "3.0.8", + "postcss-ordered-values": "2.2.3", + "postcss-reduce-idents": "2.4.0", + "postcss-reduce-initial": "1.0.1", + "postcss-reduce-transforms": "1.0.4", + "postcss-svgo": "2.1.6", + "postcss-unique-selectors": "2.0.2", + "postcss-value-parser": "3.3.0", + "postcss-zindex": "2.2.0" + } + }, + "csso": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", + "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", + "dev": true, + "requires": { + "clap": "1.2.3", + "source-map": "0.5.7" + } + }, + "cuint": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", + "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "deep-extend": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz", + "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=", + "dev": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", + "dev": true + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + } + } + }, + "del-cli": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/del-cli/-/del-cli-1.1.0.tgz", + "integrity": "sha1-J1V9aaC335ncuqHjSgnmrGWR0sQ=", + "dev": true, + "requires": { + "del": "3.0.0", + "meow": "3.7.0", + "update-notifier": "2.3.0" + }, + "dependencies": { + "del": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", + "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", + "dev": true, + "requires": { + "globby": "6.1.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "p-map": "1.2.0", + "pify": "3.0.0", + "rimraf": "2.6.2" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "dependency-graph": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.5.1.tgz", + "integrity": "sha512-nk3OjiI68T3876/tsm4Hm57ye7zc4Kl87hkcALBMCuSrN1q1NvuY5HCnSSkoJjGdrMo5gmu0WTN2cV/D76q/mw==", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "diff": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz", + "integrity": "sha512-QpVuMTEoJMF7cKzi6bvWhRulU1fZqZnvyVQgNhPaxxuTYwyjn/j1v9falseQ/uXWwPnO56RBfwtg4h/EQXmucA==", + "dev": true + }, + "doctrine": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz", + "integrity": "sha512-y0tm5Pq6ywp3qSTZ1vPgVdAnbDEoeoc5wlOHXoY1c4Wug/a7JvqHIl7BTvwodaHmejWkK/9dSb3sCYfyo/om8A==", + "dev": true, + "requires": { + "esutils": "2.0.2" + } + }, + "doiuse": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/doiuse/-/doiuse-2.6.0.tgz", + "integrity": "sha1-GJLRC2Gpo1at2/K2FJM+gfi7ODQ=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-db": "1.0.30000744", + "css-rule-stream": "1.1.0", + "duplexer2": "0.0.2", + "jsonfilter": "1.1.2", + "ldjson-stream": "1.2.1", + "lodash": "4.17.4", + "multimatch": "2.1.0", + "postcss": "5.2.18", + "source-map": "0.4.4", + "through2": "0.6.5", + "yargs": "3.32.0" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000744", + "electron-to-chromium": "1.3.24" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "os-locale": "1.4.0", + "string-width": "1.0.2", + "window-size": "0.1.4", + "y18n": "3.2.1" + } + } + } + }, + "dot-prop": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", + "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", + "dev": true, + "requires": { + "is-obj": "1.0.1" + } + }, + "duplexer": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "dev": true + }, + "duplexer2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", + "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "dev": true, + "requires": { + "readable-stream": "1.1.14" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "editorconfig": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz", + "integrity": "sha512-WkjsUNVCu+ITKDj73QDvi0trvpdDWdkDyHybDGSXPfekLCqwmpD7CP7iPbvBgosNuLcI96XTDwNa75JyFl7tEQ==", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "commander": "2.11.0", + "lru-cache": "3.2.0", + "semver": "5.4.1", + "sigmund": "1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", + "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", + "dev": true, + "requires": { + "pseudomap": "1.0.2" + } + } + } + }, + "electron-to-chromium": { + "version": "1.3.24", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.24.tgz", + "integrity": "sha1-m3uIuwXOufoBahd4M8wt3jiPIbY=", + "dev": true + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.9.0.tgz", + "integrity": "sha512-kk3IJoKo7A3pWJc0OV8yZ/VEX2oSUytfekrJiqoxBlKJMFAJVJVpGdHClCCTdv+Fn2zHfpDHHIelMFhZVfef3Q==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "es6-promise": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz", + "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.14.0.tgz", + "integrity": "sha512-Ul6CSGRjKscEyg0X/EeNs7o2XdnbTEOD1OM8cTjmx85RPcBJQrEhZLevhuJZNAE/vS2iVl5Uhgiqf3h5uLMCJQ==", + "dev": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.3.0", + "concat-stream": "1.6.0", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.0.2", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.2", + "esquery": "1.0.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.1.0", + "ignore": "3.3.5", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.0.1", + "js-yaml": "3.10.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.1.0.tgz", + "integrity": "sha512-uEuWt9mqTlPDwSqi+sHjD4nWU/1N+q0fiWI9T1mZpD2UENqX20CFD5T/ziLZvztPaBKl7ZylUi1q6Qfm7E2CiQ==", + "dev": true + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "dev": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz", + "integrity": "sha512-yUtXS15gIcij68NmXmP9Ni77AQuCN0itXbCc/jWd8C6/yKZaSNXicpC8cgvjnxVdmfsosIXrjpzFq7GcDryb6A==", + "dev": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.4.0" + } + }, + "eslint-module-utils": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", + "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz", + "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==", + "dev": true, + "requires": { + "builtin-modules": "1.1.1", + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.1", + "eslint-module-utils": "2.1.1", + "has": "1.0.1", + "lodash.cond": "4.5.2", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0" + }, + "dependencies": { + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==", + "dev": true + }, + "espree": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", + "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", + "dev": true, + "requires": { + "acorn": "5.3.0", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "estree-walker": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.2.1.tgz", + "integrity": "sha1-va/oCVOD2EFNXcLs9MkXO225QS4=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "dev": true, + "requires": { + "duplexer": "0.1.1", + "from": "0.1.7", + "map-stream": "0.1.0", + "pause-stream": "0.0.11", + "split": "0.3.3", + "stream-combiner": "0.0.4", + "through": "2.3.8" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "execall": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execall/-/execall-1.0.0.tgz", + "integrity": "sha1-c9CQTjlbPKsGWLCNCewlMH8pu3M=", + "dev": true, + "requires": { + "clone-regexp": "1.0.0" + } + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "external-editor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", + "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", + "dev": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.19", + "tmp": "0.0.33" + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extract-zip": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", + "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", + "dev": true, + "requires": { + "concat-stream": "1.6.0", + "debug": "2.6.9", + "mkdirp": "0.5.0", + "yauzl": "2.4.1" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", + "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fd-slicer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", + "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, + "requires": { + "pend": "1.2.0" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "flatten": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", + "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", + "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "dev": true + }, + "fs-extra": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", + "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "2.4.0", + "klaw": "1.3.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "gather-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gather-stream/-/gather-stream-1.0.0.tgz", + "integrity": "sha1-szmUr0V6gRVwDUEPMXczy+egkEs=", + "dev": true + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "global-dirs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.0.tgz", + "integrity": "sha1-ENNAOeDfBCcuJizyQiT3IJQ0308=", + "dev": true, + "requires": { + "ini": "1.3.4" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globby": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-4.1.0.tgz", + "integrity": "sha1-CA9UVJ7BuCpsYOYx/ILhIR2+lfg=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "6.0.4", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "globjoin": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", + "integrity": "sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM=", + "dev": true + }, + "got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "requires": { + "create-error-class": "3.0.2", + "duplexer3": "0.1.4", + "get-stream": "3.0.0", + "is-redirect": "1.0.0", + "is-retry-allowed": "1.1.0", + "is-stream": "1.1.0", + "lowercase-keys": "1.0.0", + "safe-buffer": "5.1.1", + "timed-out": "4.0.1", + "unzip-response": "2.0.1", + "url-parse-lax": "1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, + "requires": { + "ajv": "5.2.3", + "har-schema": "2.0.0" + } + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "hasha": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", + "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true, + "requires": { + "is-stream": "1.1.0", + "pinkie-promise": "2.0.1" + } + }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, + "requires": { + "boom": "4.3.1", + "cryptiles": "3.1.2", + "hoek": "4.2.0", + "sntp": "2.1.0" + } + }, + "hoek": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", + "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "html-comment-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", + "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=", + "dev": true + }, + "html-tags": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-2.0.0.tgz", + "integrity": "sha1-ELMKOGCF9Dzt41PMj6fLDe7qZos=", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "ignore": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz", + "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", + "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.0", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.4", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "irregular-plurals": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.3.0.tgz", + "integrity": "sha512-njf5A+Mxb3kojuHd1DzISjjIl+XhyzovXEOyPPSzdQozq/Lf2tN27mOrAAsxEPZxpn6I4MGzs1oo9TxXxPFpaA==", + "dev": true + }, + "is-absolute-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", + "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.10.0" + } + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "dev": true + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "requires": { + "global-dirs": "0.1.0", + "is-path-inside": "1.0.0" + } + }, + "is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.0" + } + }, + "is-path-inside": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", + "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } + }, + "is-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", + "integrity": "sha1-/S2INUXEa6xaYz57mgnof6LLUGk=", + "dev": true + }, + "is-resolvable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", + "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==", + "dev": true + }, + "is-retry-allowed": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz", + "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ=", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-supported-regexp-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz", + "integrity": "sha1-i1IMhfrnolM4LUsCZS4EVXbhO7g=", + "dev": true + }, + "is-svg": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", + "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", + "dev": true, + "requires": { + "html-comment-regex": "1.1.1" + } + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isnumeric": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/isnumeric/-/isnumeric-0.2.0.tgz", + "integrity": "sha1-ojR7o2DeGeM9D/1ZD933dVy/LmQ=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-base64": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz", + "integrity": "sha512-Y2/+DnfJJXT1/FCwUebUhLWb3QihxiSC42+ctHLGogmW2jPY6LCapMdFZXRvVP2z6qyKW7s6qncE/9gSqZiArw==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", + "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "2.7.3" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz", + "integrity": "sha512-xyQpxeWWMKyJps9CuGJYeng6ssI5bpqS9ltQpdVQ90t4ql6NdnxFKh95JcRt2cun/DjMVNrdjniLPuMA69xmCw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "0.0.0" + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonfile": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", + "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "jsonfilter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/jsonfilter/-/jsonfilter-1.1.2.tgz", + "integrity": "sha1-Ie987cdRk4E8dZMulqmL4gW6WhE=", + "dev": true, + "requires": { + "JSONStream": "0.8.4", + "minimist": "1.2.0", + "stream-combiner": "0.2.2", + "through2": "0.6.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "dev": true, + "requires": { + "duplexer": "0.1.1", + "through": "2.3.8" + } + } + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "dev": true + }, + "jsonparse": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-0.0.5.tgz", + "integrity": "sha1-MwVCrT8KZUZlt3jz6y2an6UHrGQ=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kew": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + }, + "klaw": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", + "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "known-css-properties": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.2.0.tgz", + "integrity": "sha512-UTCzU28rRI9wkb8qSGoZa9pgWvxr4LjP2MEhi9XHb/1XMOJy0uTnIxaxzj8My/PORG+kQG6VzAcGvRw66eIOfA==", + "dev": true + }, + "latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "requires": { + "package-json": "4.0.1" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "ldjson-stream": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ldjson-stream/-/ldjson-stream-1.2.1.tgz", + "integrity": "sha1-kb7O2lrE7SsX5kn7d356v6AYnCs=", + "dev": true, + "requires": { + "split2": "0.2.1", + "through2": "0.6.5" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lodash._reinterpolate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", + "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", + "dev": true + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "dev": true + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=", + "dev": true + }, + "lodash.template": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", + "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", + "dev": true, + "requires": { + "lodash._reinterpolate": "3.0.0", + "lodash.templatesettings": "4.1.0" + } + }, + "lodash.templatesettings": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", + "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", + "dev": true, + "requires": { + "lodash._reinterpolate": "3.0.0" + } + }, + "lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=", + "dev": true + }, + "log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "dev": true, + "requires": { + "chalk": "1.1.3" + } + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=", + "dev": true + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "macaddress": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", + "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", + "dev": true + }, + "make-dir": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.1.0.tgz", + "integrity": "sha512-0Pkui4wLJ7rxvmfUvs87skoEaxmu0hCUApF8nonzpl7q//FWp9zu8W61Scz4sd/kUiqDxvUhtoam2efDyiBzcA==", + "dev": true, + "requires": { + "pify": "3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "dev": true + }, + "math-expression-evaluator": { + "version": "1.2.17", + "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", + "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=", + "dev": true + }, + "mathml-tag-names": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mathml-tag-names/-/mathml-tag-names-2.0.1.tgz", + "integrity": "sha1-jUEmgWi/htEQK5gQnijlMeejRXg=", + "dev": true + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "dev": true, + "requires": { + "array-differ": "1.0.0", + "array-union": "1.0.2", + "arrify": "1.0.1", + "minimatch": "3.0.4" + } + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "nested-error-stacks": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.2.tgz", + "integrity": "sha1-GfYZWRUZ8JZ2mlupqG5u7sgjw88=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "node-qunit-phantomjs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-qunit-phantomjs/-/node-qunit-phantomjs-2.0.0.tgz", + "integrity": "sha512-xZV0J8fBbe8h04IkBxLtwvGVbP0ViUhkJzjFx/tb7uWT02w6iMt5X6HDmdTZuQXBMsgahyaIGjW30l3HSlj2yA==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "minimist": "1.2.0", + "phantomjs-prebuilt": "2.1.16", + "qunit-phantomjs-runner": "2.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "qunit-phantomjs-runner": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/qunit-phantomjs-runner/-/qunit-phantomjs-runner-2.3.1.tgz", + "integrity": "sha512-RLg51606zm6/HwZi29NciAMAqifyJE1oGg77tEuk05vEa7kuqEaI0Mkjw976Ynnq7GXurATnbFd+471c024tBQ==", + "dev": true, + "requires": { + "qunit-reporter-junit": "1.1.1" + } + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "normalize-selector": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/normalize-selector/-/normalize-selector-0.2.0.tgz", + "integrity": "sha1-0LFF62kRicY6eNIB3E/bEpPvDAM=", + "dev": true + }, + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "prepend-http": "1.0.4", + "query-string": "4.3.4", + "sort-keys": "1.1.2" + } + }, + "npm-run-all": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.2.tgz", + "integrity": "sha512-Z2aRlajMK4SQ8u19ZA75NZZu7wupfCNQWdYosIi8S6FgBdGf/8Y6Hgyjdc8zU2cYmIRVCx1nM80tJPkdEd+UYg==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "chalk": "2.3.0", + "cross-spawn": "5.1.0", + "memorystream": "0.3.1", + "minimatch": "3.0.4", + "ps-tree": "1.1.0", + "read-pkg": "3.0.0", + "shell-quote": "1.6.1", + "string.prototype.padend": "3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "4.0.0", + "pify": "3.0.0", + "strip-bom": "3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "1.3.1", + "json-parse-better-errors": "1.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "4.0.0", + "normalize-package-data": "2.4.0", + "path-type": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "2.0.1" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onecolor": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/onecolor/-/onecolor-3.0.4.tgz", + "integrity": "sha1-daRvgNpseqpbTarhekcZi9llJJQ=", + "dev": true + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "ora": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-1.3.0.tgz", + "integrity": "sha1-gAeN0rkqk0r2ajrXKluRBpTt5Ro=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "cli-cursor": "2.1.0", + "cli-spinners": "1.1.0", + "log-symbols": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "dev": true, + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "p-map": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz", + "integrity": "sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA==", + "dev": true + }, + "package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "requires": { + "got": "6.7.1", + "registry-auth-token": "3.3.1", + "registry-url": "3.1.0", + "semver": "5.4.1" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "dev": true, + "requires": { + "through": "2.3.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "phantomjs-prebuilt": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", + "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "dev": true, + "requires": { + "es6-promise": "4.1.1", + "extract-zip": "1.6.6", + "fs-extra": "1.0.0", + "hasha": "2.2.0", + "kew": "0.7.0", + "progress": "1.1.8", + "request": "2.83.0", + "request-progress": "2.0.1", + "which": "1.3.0" + }, + "dependencies": { + "progress": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pipetteur": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pipetteur/-/pipetteur-2.0.3.tgz", + "integrity": "sha1-GVV2CVno0aEcsqUOyD7sRwYz5J8=", + "dev": true, + "requires": { + "onecolor": "3.0.4", + "synesthesia": "1.0.1" + } + }, + "pixrem": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pixrem/-/pixrem-4.0.1.tgz", + "integrity": "sha1-LaSh3m7EQjxfw3lOkwuB1EkOxoY=", + "dev": true, + "requires": { + "browserslist": "2.5.0", + "postcss": "6.0.13", + "reduce-css-calc": "1.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pleeease-filters": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/pleeease-filters/-/pleeease-filters-4.0.0.tgz", + "integrity": "sha1-ZjKy+wVkjSdY2GU4T7zteeHMrsc=", + "dev": true, + "requires": { + "onecolor": "3.0.4", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "plur": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", + "integrity": "sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=", + "dev": true, + "requires": { + "irregular-plurals": "1.3.0" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "dev": true, + "requires": { + "chalk": "1.1.3", + "js-base64": "2.3.2", + "source-map": "0.5.7", + "supports-color": "3.2.3" + }, + "dependencies": { + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + } + } + }, + "postcss-apply": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/postcss-apply/-/postcss-apply-0.8.0.tgz", + "integrity": "sha1-FOVEu7XLbxweBIhXll15rgZrE0M=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "balanced-match": "0.4.2", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-attribute-case-insensitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-2.0.0.tgz", + "integrity": "sha1-lNxCLI+QmX8WvTOjZUu77AhJY7Q=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-selector-parser": "2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-calc": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", + "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-message-helpers": "2.0.0", + "reduce-css-calc": "1.3.0" + } + }, + "postcss-cli": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-4.1.1.tgz", + "integrity": "sha1-uUvY//u3rB9i8mB+ePyTl/f2Ol0=", + "dev": true, + "requires": { + "chalk": "2.1.0", + "chokidar": "1.7.0", + "dependency-graph": "0.5.1", + "fs-extra": "4.0.2", + "get-stdin": "5.0.1", + "globby": "6.1.0", + "ora": "1.3.0", + "postcss": "6.0.13", + "postcss-load-config": "1.2.0", + "postcss-reporter": "5.0.0", + "pretty-hrtime": "1.0.3", + "read-cache": "1.0.0", + "yargs": "8.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "fs-extra": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", + "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11" + } + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-function": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-function/-/postcss-color-function-4.0.0.tgz", + "integrity": "sha1-fgEG9Pah7LGtWzqFU6zl6Ciq4Yc=", + "dev": true, + "requires": { + "css-color-function": "1.3.3", + "postcss": "6.0.13", + "postcss-message-helpers": "2.0.0", + "postcss-value-parser": "3.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-gray": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-gray/-/postcss-color-gray-4.0.0.tgz", + "integrity": "sha1-aBvzBQl91mv+8OHmKC1dmbWsyV0=", + "dev": true, + "requires": { + "color": "1.0.3", + "postcss": "6.0.13", + "postcss-message-helpers": "2.0.0", + "reduce-function-call": "1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-1.0.3.tgz", + "integrity": "sha1-5I6DLYXxTvaU+0aIEcLVz+cptV0=", + "dev": true, + "requires": { + "color-convert": "1.9.0", + "color-string": "1.5.2" + } + }, + "color-string": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.2.tgz", + "integrity": "sha1-JuRYFLw8mny9Z1FkikFDRRSnc6k=", + "dev": true, + "requires": { + "color-name": "1.1.3", + "simple-swizzle": "0.2.2" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-hex-alpha": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-3.0.0.tgz", + "integrity": "sha1-HlPmyKyyN5Vej9CLfs2xuLgwn5U=", + "dev": true, + "requires": { + "color": "1.0.3", + "postcss": "6.0.13", + "postcss-message-helpers": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-1.0.3.tgz", + "integrity": "sha1-5I6DLYXxTvaU+0aIEcLVz+cptV0=", + "dev": true, + "requires": { + "color-convert": "1.9.0", + "color-string": "1.5.2" + } + }, + "color-string": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.2.tgz", + "integrity": "sha1-JuRYFLw8mny9Z1FkikFDRRSnc6k=", + "dev": true, + "requires": { + "color-name": "1.1.3", + "simple-swizzle": "0.2.2" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-hsl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hsl/-/postcss-color-hsl-2.0.0.tgz", + "integrity": "sha1-EnA2ZvoxBDDj8wpFTawThjF9WEQ=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-value-parser": "3.3.0", + "units-css": "0.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-hwb": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-hwb/-/postcss-color-hwb-3.0.0.tgz", + "integrity": "sha1-NAKxnvTYSXVAwftQcr6YY8qVVx4=", + "dev": true, + "requires": { + "color": "1.0.3", + "postcss": "6.0.13", + "postcss-message-helpers": "2.0.0", + "reduce-function-call": "1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "color": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/color/-/color-1.0.3.tgz", + "integrity": "sha1-5I6DLYXxTvaU+0aIEcLVz+cptV0=", + "dev": true, + "requires": { + "color-convert": "1.9.0", + "color-string": "1.5.2" + } + }, + "color-string": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.2.tgz", + "integrity": "sha1-JuRYFLw8mny9Z1FkikFDRRSnc6k=", + "dev": true, + "requires": { + "color-name": "1.1.3", + "simple-swizzle": "0.2.2" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-rebeccapurple": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-3.0.0.tgz", + "integrity": "sha1-7rrwPTY7QwC5Z5K9MIHBntZlE9M=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-value-parser": "3.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-rgb": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rgb/-/postcss-color-rgb-2.0.0.tgz", + "integrity": "sha1-FFOcinExSUtILg3RzCZf9lFLUmM=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-value-parser": "3.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-color-rgba-fallback": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-color-rgba-fallback/-/postcss-color-rgba-fallback-3.0.0.tgz", + "integrity": "sha1-N9XJNToHoJJwkSqCYGu0Kg1wLAQ=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-value-parser": "3.3.0", + "rgb-hex": "2.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-colormin": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", + "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", + "dev": true, + "requires": { + "colormin": "1.1.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-convert-values": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", + "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-cssnext": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postcss-cssnext/-/postcss-cssnext-3.0.2.tgz", + "integrity": "sha512-jA6kGdcUMZqLUgw6MdpyNWGFhk0LIITVhC/jTnLRZLoXSTR88qT2cFOn3LbY06udt1PVdTCHDG3plBjxVKf8BQ==", + "dev": true, + "requires": { + "autoprefixer": "7.1.5", + "caniuse-api": "2.0.0", + "chalk": "2.1.0", + "pixrem": "4.0.1", + "pleeease-filters": "4.0.0", + "postcss": "6.0.13", + "postcss-apply": "0.8.0", + "postcss-attribute-case-insensitive": "2.0.0", + "postcss-calc": "6.0.0", + "postcss-color-function": "4.0.0", + "postcss-color-gray": "4.0.0", + "postcss-color-hex-alpha": "3.0.0", + "postcss-color-hsl": "2.0.0", + "postcss-color-hwb": "3.0.0", + "postcss-color-rebeccapurple": "3.0.0", + "postcss-color-rgb": "2.0.0", + "postcss-color-rgba-fallback": "3.0.0", + "postcss-custom-media": "6.0.0", + "postcss-custom-properties": "6.2.0", + "postcss-custom-selectors": "4.0.1", + "postcss-font-family-system-ui": "2.0.1", + "postcss-font-variant": "3.0.0", + "postcss-image-set-polyfill": "0.3.5", + "postcss-initial": "2.0.0", + "postcss-media-minmax": "3.0.0", + "postcss-nesting": "4.2.1", + "postcss-pseudo-class-any-link": "4.0.0", + "postcss-pseudoelements": "5.0.0", + "postcss-replace-overflow-wrap": "2.0.0", + "postcss-selector-matches": "3.0.1", + "postcss-selector-not": "3.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "autoprefixer": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-7.1.5.tgz", + "integrity": "sha512-sMN453qIm8Z+tunzYWW+Y490wWkICHhCYm/VohLjjl+N7ARSFuF5au7E6tr7oEbeeXj8mNjpSw2kxjJaO6YCOw==", + "dev": true, + "requires": { + "browserslist": "2.5.0", + "caniuse-lite": "1.0.30000744", + "normalize-range": "0.1.2", + "num2fraction": "1.2.2", + "postcss": "6.0.13", + "postcss-value-parser": "3.3.0" + } + }, + "caniuse-api": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-2.0.0.tgz", + "integrity": "sha1-sd21pZZrFvSNxJmERNS7xsfZ2DQ=", + "dev": true, + "requires": { + "browserslist": "2.5.0", + "caniuse-lite": "1.0.30000744", + "lodash.memoize": "4.1.2", + "lodash.uniq": "4.5.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "postcss-calc": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-6.0.0.tgz", + "integrity": "sha1-toGyecbST74OM+2QRYA3BURdYTs=", + "dev": true, + "requires": { + "css-unit-converter": "1.1.1", + "postcss": "6.0.13", + "postcss-selector-parser": "2.2.3", + "reduce-css-calc": "2.0.5" + } + }, + "reduce-css-calc": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.0.5.tgz", + "integrity": "sha1-M8l4OMXUxxGlwU74XOT95BSD970=", + "dev": true, + "requires": { + "css-unit-converter": "1.1.1", + "postcss-value-parser": "3.3.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-custom-media": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-6.0.0.tgz", + "integrity": "sha1-vlMnhBEOyylQRPtTlaGABushpzc=", + "dev": true, + "requires": { + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-custom-properties": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-6.2.0.tgz", + "integrity": "sha512-eNR2h9T9ciKMoQEORrPjH33XeN/nuvVuxArOKmHtsFbGbNss631tgTrKou3/pmjAZbA4QQkhLIkPQkIk3WW+8w==", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-custom-selectors": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-4.0.1.tgz", + "integrity": "sha1-eBOC+UxS5yfvXKR3bqKt9JphE4I=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-selector-matches": "3.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-discard-comments": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", + "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-duplicates": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", + "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-empty": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", + "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-overridden": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", + "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-discard-unused": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", + "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "uniqs": "2.0.0" + } + }, + "postcss-filter-plugins": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", + "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "uniqid": "4.1.1" + } + }, + "postcss-font-family-system-ui": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/postcss-font-family-system-ui/-/postcss-font-family-system-ui-2.0.1.tgz", + "integrity": "sha1-MYoHX9y4S4ZKqCOlGTXvClhy6RE=", + "dev": true, + "requires": { + "lodash": "4.17.4", + "postcss": "6.0.13", + "postcss-value-parser": "3.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-font-variant": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-3.0.0.tgz", + "integrity": "sha1-CMzIj2BQuoLtjvLMdsDGprQfGD4=", + "dev": true, + "requires": { + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-header": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postcss-header/-/postcss-header-1.0.0.tgz", + "integrity": "sha512-YUcU2oHQNsNVUDPdQg6/TXBWvI7dBGf2bsLQdVlLiLM5kiGLGCcszYDlVTaicmXpKANdS1T7bxpJtCacrMButw==", + "dev": true, + "requires": { + "babel-register": "6.26.0", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-image-set-polyfill": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/postcss-image-set-polyfill/-/postcss-image-set-polyfill-0.3.5.tgz", + "integrity": "sha1-Dxk0E3AM8fgr05Bm7wFtZaShgYE=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-media-query-parser": "0.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-initial": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-2.0.0.tgz", + "integrity": "sha1-cnFfczbgu3k1HZnuZcSiU6hEG6Q=", + "dev": true, + "requires": { + "lodash.template": "4.4.0", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-less": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/postcss-less/-/postcss-less-0.14.0.tgz", + "integrity": "sha1-xjGwicbM5CK5oQ86lY0r7dOBkyQ=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-load-config": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", + "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1", + "postcss-load-options": "1.2.0", + "postcss-load-plugins": "2.3.0" + } + }, + "postcss-load-options": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", + "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-load-plugins": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", + "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", + "dev": true, + "requires": { + "cosmiconfig": "2.2.2", + "object-assign": "4.1.1" + } + }, + "postcss-media-minmax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-3.0.0.tgz", + "integrity": "sha1-Z1JWA3pD70C8Twdgv9BtTcadSNI=", + "dev": true, + "requires": { + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ=", + "dev": true + }, + "postcss-merge-idents": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", + "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-merge-longhand": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", + "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-merge-rules": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", + "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "caniuse-api": "1.6.1", + "postcss": "5.2.18", + "postcss-selector-parser": "2.2.3", + "vendors": "1.0.1" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000744", + "electron-to-chromium": "1.3.24" + } + } + } + }, + "postcss-message-helpers": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", + "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=", + "dev": true + }, + "postcss-minify-font-values": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", + "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-minify-gradients": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", + "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-minify-params": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", + "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0", + "uniqs": "2.0.0" + } + }, + "postcss-minify-selectors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", + "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "has": "1.0.1", + "postcss": "5.2.18", + "postcss-selector-parser": "2.2.3" + } + }, + "postcss-nesting": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-4.2.1.tgz", + "integrity": "sha512-IkyWXICwagCnlaviRexi7qOdwPw3+xVVjgFfGsxmztvRVaNxAlrypOIKqDE5mxY+BVxnId1rnUKBRQoNE2VDaA==", + "dev": true, + "requires": { + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-normalize-charset": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", + "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-normalize-url": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", + "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", + "dev": true, + "requires": { + "is-absolute-url": "2.1.0", + "normalize-url": "1.9.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-ordered-values": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", + "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-4.0.0.tgz", + "integrity": "sha1-kVKgYT00UHIFE+iJKFS65C0O5o4=", + "dev": true, + "requires": { + "postcss": "6.0.13", + "postcss-selector-parser": "2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-pseudoelements": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-pseudoelements/-/postcss-pseudoelements-5.0.0.tgz", + "integrity": "sha1-7vGU6NUkZFylIKlJ6V5RjoEkAss=", + "dev": true, + "requires": { + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-reduce-idents": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", + "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", + "dev": true, + "requires": { + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-reduce-initial": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", + "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "postcss-reduce-transforms": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", + "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0" + } + }, + "postcss-replace-overflow-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-2.0.0.tgz", + "integrity": "sha1-eU22+qVPjbEAhUOSqTr0V2i04ls=", + "dev": true, + "requires": { + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-reporter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-5.0.0.tgz", + "integrity": "sha512-rBkDbaHAu5uywbCR2XE8a25tats3xSOsGNx6mppK6Q9kSFGKc/FyAzfci+fWM2l+K402p1D0pNcfDGxeje5IKg==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "lodash": "4.17.4", + "log-symbols": "2.1.0", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "log-symbols": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.1.0.tgz", + "integrity": "sha512-zLeLrzMA1A2vRF1e/0Mo+LNINzi6jzBylHj5WqvQ/WK/5WCZt8si9SyN4p9llr/HRYvVR1AoXHRHl4WTHyQAzQ==", + "dev": true, + "requires": { + "chalk": "2.1.0" + } + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-resolve-nested-selector": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", + "integrity": "sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4=", + "dev": true + }, + "postcss-scss": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-1.0.2.tgz", + "integrity": "sha1-/0XPM1S4ee6JpOtoaA9GrJuxT5Q=", + "dev": true, + "requires": { + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-selector-matches": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-matches/-/postcss-selector-matches-3.0.1.tgz", + "integrity": "sha1-5WNAEeE5UIgYYbvdWMLQER/8lqs=", + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-selector-not": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-3.0.1.tgz", + "integrity": "sha1-Lk2y8JZTNsAefOx9tsYN/3ZzNdk=", + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "postcss": "6.0.13" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-selector-parser": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", + "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", + "dev": true, + "requires": { + "flatten": "1.0.2", + "indexes-of": "1.0.1", + "uniq": "1.0.1" + } + }, + "postcss-sorting": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-2.1.0.tgz", + "integrity": "sha1-MrHpr6kTuyJaatB21QPY+YO7SoI=", + "dev": true, + "requires": { + "lodash": "4.17.4", + "postcss": "5.2.18" + } + }, + "postcss-svgo": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", + "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", + "dev": true, + "requires": { + "is-svg": "2.1.0", + "postcss": "5.2.18", + "postcss-value-parser": "3.3.0", + "svgo": "0.7.2" + } + }, + "postcss-unique-selectors": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", + "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", + "dev": true, + "requires": { + "alphanum-sort": "1.0.2", + "postcss": "5.2.18", + "uniqs": "2.0.0" + } + }, + "postcss-url": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.3.0.tgz", + "integrity": "sha512-VBP6uf6iL3AZra23nkPkOEkS/5azj1xf/toRrjfkolfFEgg9Gyzg9UhJZeIsz12EGKZTNVeGbPa2XtaZm/iZvg==", + "dev": true, + "requires": { + "mime": "1.4.1", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "postcss": "6.0.14", + "xxhashjs": "0.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss": { + "version": "6.0.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz", + "integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "source-map": "0.6.1", + "supports-color": "4.5.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "postcss-value-parser": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", + "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=", + "dev": true + }, + "postcss-zindex": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", + "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", + "dev": true, + "requires": { + "has": "1.0.1", + "postcss": "5.2.18", + "uniqs": "2.0.0" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "private": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.7.tgz", + "integrity": "sha1-aM5eih7woju1cMwoU3tTMqumPvE=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true + }, + "ps-tree": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", + "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", + "dev": true, + "requires": { + "event-stream": "3.3.4" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "q": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", + "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=", + "dev": true + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "4.1.1", + "strict-uri-encode": "1.1.0" + } + }, + "qunit-reporter-junit": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/qunit-reporter-junit/-/qunit-reporter-junit-1.1.1.tgz", + "integrity": "sha1-7rYiZFeJaZPnlaEZQPGK9q+lebQ=", + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + } + } + }, + "rc": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.2.tgz", + "integrity": "sha1-2M6ctX6NZNnHut2YdsfDTL48cHc=", + "dev": true, + "requires": { + "deep-extend": "0.4.2", + "ini": "1.3.4", + "minimist": "1.2.0", + "strip-json-comments": "2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-file-stdin": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/read-file-stdin/-/read-file-stdin-0.2.1.tgz", + "integrity": "sha1-JezP86FTtoCa+ssj7hU4fbng7mE=", + "dev": true, + "requires": { + "gather-stream": "1.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "reduce-css-calc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", + "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", + "dev": true, + "requires": { + "balanced-match": "0.4.2", + "math-expression-evaluator": "1.2.17", + "reduce-function-call": "1.0.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + } + } + }, + "reduce-function-call": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", + "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", + "dev": true, + "requires": { + "balanced-match": "0.4.2" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + } + } + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.7" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "registry-auth-token": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.1.tgz", + "integrity": "sha1-+w0yie4Nmtosu1KvXf5mywcNMAY=", + "dev": true, + "requires": { + "rc": "1.2.2", + "safe-buffer": "5.1.1" + } + }, + "registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "requires": { + "rc": "1.2.2" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.83.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", + "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", + "dev": true, + "requires": { + "aws-sign2": "0.7.0", + "aws4": "1.6.0", + "caseless": "0.12.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.3.1", + "har-validator": "5.0.3", + "hawk": "6.0.2", + "http-signature": "1.2.0", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "performance-now": "2.1.0", + "qs": "6.5.1", + "safe-buffer": "5.1.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.6.0", + "uuid": "3.1.0" + } + }, + "request-progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", + "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true, + "requires": { + "throttleit": "1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-from-string": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", + "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=", + "dev": true + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", + "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rgb": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/rgb/-/rgb-0.1.0.tgz", + "integrity": "sha1-vieykej+/+rBvZlylyG/pA/AN7U=", + "dev": true + }, + "rgb-hex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/rgb-hex/-/rgb-hex-2.1.0.tgz", + "integrity": "sha1-x3PF/iJoolV42SU5qCp6XOU77aY=", + "dev": true + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.2" + }, + "dependencies": { + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "rollup": { + "version": "0.53.3", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-0.53.3.tgz", + "integrity": "sha512-MADFV0jpoh1QDB6U0U6YamGihGetxHEYgwTcGsc7map6JFIydPEfGNshK+ozxv1RKeUOQKn1vRb85IAcdjL22Q==", + "dev": true + }, + "rollup-plugin-babel": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/rollup-plugin-babel/-/rollup-plugin-babel-3.0.3.tgz", + "integrity": "sha512-5kzM/Rr4jQSRPLc2eN5NuD+CI/6AAy7S1O18Ogu4U3nq1Q42VJn0C9EMtqnvxtfwf1XrezOtdA9ro1VZI5B0mA==", + "dev": true, + "requires": { + "rollup-pluginutils": "1.5.2" + } + }, + "rollup-pluginutils": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-1.5.2.tgz", + "integrity": "sha1-HhVud4+UtyVb+hs9AXi+j1xVJAg=", + "dev": true, + "requires": { + "estree-walker": "0.2.1", + "minimatch": "3.0.4" + } + }, + "rollup-watch": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/rollup-watch/-/rollup-watch-4.3.1.tgz", + "integrity": "sha512-6yjnIwfjpSrqA8IafyIu7fsEyeImNR4aDjA1bQ7KWeVuiA+Clfsx8+PGQkyABWIQzmauQ//tIJ5wAxLXsXs8qQ==", + "dev": true, + "requires": { + "chokidar": "1.7.0", + "require-relative": "0.8.7", + "rollup-pluginutils": "2.0.1" + }, + "dependencies": { + "estree-walker": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.3.1.tgz", + "integrity": "sha1-5rGlHPcpJSTnI3wxLl/mZgwc4ao=", + "dev": true + }, + "rollup-pluginutils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.0.1.tgz", + "integrity": "sha1-fslbNXP2VDpGpkYb2afFRFJdD8A=", + "dev": true, + "requires": { + "estree-walker": "0.3.1", + "micromatch": "2.3.11" + } + } + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "requires": { + "semver": "5.4.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shell-quote": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", + "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", + "dev": true, + "requires": { + "array-filter": "0.0.1", + "array-map": "0.0.0", + "array-reduce": "0.0.0", + "jsonify": "0.0.0" + } + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dev": true, + "requires": { + "is-arrayish": "0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.1.tgz", + "integrity": "sha1-wt/DhquqDD4zxI2z/ocFnmkGXv0=", + "dev": true + } + } + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, + "requires": { + "hoek": "4.2.0" + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "1.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "specificity": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/specificity/-/specificity-0.3.2.tgz", + "integrity": "sha512-Nc/QN/A425Qog7j9aHmwOrlwX2e7pNI47ciwxwy4jOlvbbMHkNNJchit+FX+UjF3IAdiaaV5BKeWuDUnws6G1A==", + "dev": true + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "dev": true, + "requires": { + "through": "2.3.8" + } + }, + "split2": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz", + "integrity": "sha1-At2smtwD7Au3jBKC7Aecpuha6QA=", + "dev": true, + "requires": { + "through2": "0.6.5" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + } + }, + "stdin": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/stdin/-/stdin-0.0.1.tgz", + "integrity": "sha1-0wQZgarsPf28d6GzjWNy449ftx4=", + "dev": true + }, + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dev": true, + "requires": { + "duplexer": "0.1.1" + } + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + } + } + } + }, + "string.prototype.padend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", + "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.9.0", + "function-bind": "1.1.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "style-search": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", + "integrity": "sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI=", + "dev": true + }, + "stylefmt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/stylefmt/-/stylefmt-6.0.0.tgz", + "integrity": "sha1-yFHpwteLiplQL3S6PYY7MBY+7JM=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "css-color-list": "0.0.1", + "diff": "3.4.0", + "editorconfig": "0.13.3", + "globby": "6.1.0", + "minimist": "1.2.0", + "postcss": "6.0.13", + "postcss-scss": "1.0.2", + "postcss-sorting": "2.1.0", + "postcss-value-parser": "3.3.0", + "stdin": "0.0.1", + "stylelint": "7.13.0", + "stylelint-order": "0.4.4" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "postcss": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.13.tgz", + "integrity": "sha512-nHsrD1PPTMSJDfU+osVsLtPkSP9YGeoOz4FDLN4r1DW4N5vqL1J+gACzTQHsfwIiWG/0/nV4yCzjTMo1zD8U1g==", + "dev": true, + "requires": { + "chalk": "2.1.0", + "source-map": "0.6.1", + "supports-color": "4.4.0" + }, + "dependencies": { + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "stylehacks": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-2.3.2.tgz", + "integrity": "sha1-ZMg+BDimjJ7fRJ6MVSp9mrYAmws=", + "dev": true, + "requires": { + "browserslist": "1.7.7", + "chalk": "1.1.3", + "log-symbols": "1.0.2", + "minimist": "1.2.0", + "plur": "2.1.2", + "postcss": "5.2.18", + "postcss-reporter": "1.4.1", + "postcss-selector-parser": "2.2.3", + "read-file-stdin": "0.2.1", + "text-table": "0.2.0", + "write-file-stdout": "0.0.2" + }, + "dependencies": { + "browserslist": { + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", + "dev": true, + "requires": { + "caniuse-db": "1.0.30000744", + "electron-to-chromium": "1.3.24" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "postcss-reporter": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-1.4.1.tgz", + "integrity": "sha1-wTbwpbFhkV83ndN2XGEHX357mvI=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.4", + "log-symbols": "1.0.2", + "postcss": "5.2.18" + } + } + } + }, + "stylelint": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-7.13.0.tgz", + "integrity": "sha1-ER+Xttpy53XICADWu29fhpmXeF0=", + "dev": true, + "requires": { + "autoprefixer": "6.7.7", + "balanced-match": "0.4.2", + "chalk": "2.1.0", + "colorguard": "1.2.0", + "cosmiconfig": "2.2.2", + "debug": "2.6.9", + "doiuse": "2.6.0", + "execall": "1.0.0", + "file-entry-cache": "2.0.0", + "get-stdin": "5.0.1", + "globby": "6.1.0", + "globjoin": "0.1.4", + "html-tags": "2.0.0", + "ignore": "3.3.5", + "imurmurhash": "0.1.4", + "known-css-properties": "0.2.0", + "lodash": "4.17.4", + "log-symbols": "1.0.2", + "mathml-tag-names": "2.0.1", + "meow": "3.7.0", + "micromatch": "2.3.11", + "normalize-selector": "0.2.0", + "pify": "2.3.0", + "postcss": "5.2.18", + "postcss-less": "0.14.0", + "postcss-media-query-parser": "0.2.3", + "postcss-reporter": "3.0.0", + "postcss-resolve-nested-selector": "0.1.1", + "postcss-scss": "0.4.1", + "postcss-selector-parser": "2.2.3", + "postcss-value-parser": "3.3.0", + "resolve-from": "3.0.0", + "specificity": "0.3.2", + "string-width": "2.1.1", + "style-search": "0.1.0", + "stylehacks": "2.3.2", + "sugarss": "0.2.0", + "svg-tags": "1.0.0", + "table": "4.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "balanced-match": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", + "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=", + "dev": true + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "get-stdin": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-5.0.1.tgz", + "integrity": "sha1-Ei4WFZHiH/TFJTAwVpPyDmOTo5g=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "postcss-reporter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-3.0.0.tgz", + "integrity": "sha1-CeoPN6RExWk4eGBuCbAY6+/3z48=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "lodash": "4.17.4", + "log-symbols": "1.0.2", + "postcss": "5.2.18" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "postcss-scss": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-0.4.1.tgz", + "integrity": "sha1-rXcbgfD3L19IRdCKpg+TVXZT1Uw=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "stylelint-order": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-0.4.4.tgz", + "integrity": "sha1-2338oFQbUGIBDH4uIedFeR/AiKw=", + "dev": true, + "requires": { + "lodash": "4.17.4", + "postcss": "5.2.18", + "stylelint": "7.13.0" + } + }, + "sugarss": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/sugarss/-/sugarss-0.2.0.tgz", + "integrity": "sha1-rDQjdWMyfG/4l7ZHQr9q7BkK054=", + "dev": true, + "requires": { + "postcss": "5.2.18" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "svg-tags": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", + "integrity": "sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=", + "dev": true + }, + "svgo": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", + "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", + "dev": true, + "requires": { + "coa": "1.0.4", + "colors": "1.1.2", + "csso": "2.3.2", + "js-yaml": "3.7.0", + "mkdirp": "0.5.1", + "sax": "1.2.4", + "whet.extend": "0.9.9" + } + }, + "synesthesia": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/synesthesia/-/synesthesia-1.0.1.tgz", + "integrity": "sha1-XvlepUjA1cbm+btLDQcx3/hkp3c=", + "dev": true, + "requires": { + "css-color-names": "0.0.3" + }, + "dependencies": { + "css-color-names": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.3.tgz", + "integrity": "sha1-3gzvFvTYqoIioyDVttfpu62nufY=", + "dev": true + } + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "5.2.3", + "ajv-keywords": "2.1.0", + "chalk": "2.1.0", + "lodash": "4.17.4", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.1.0.tgz", + "integrity": "sha512-LUHGS/dge4ujbXMJrnihYMcL4AoOweGnw9Tp3kQuqy1Kx5c1qKjqvMJZ6nVJPMWJtKCTN72ZogH3oeSO9g9rXQ==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.4.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", + "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "requires": { + "execa": "0.7.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", + "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", + "dev": true, + "requires": { + "readable-stream": "1.0.34", + "xtend": "4.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "uglify-js": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.3.4.tgz", + "integrity": "sha512-hfIwuAQI5dlXP30UtdmWoYF9k+ypVqBXIdmd6ZKBiaNHHvA8ty7ZloMe3+7S5AEKVkxHbjByl4DfRHQ7QpZquw==", + "dev": true, + "requires": { + "commander": "2.12.2", + "source-map": "0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "uniqid": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", + "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", + "dev": true, + "requires": { + "macaddress": "0.2.8" + } + }, + "uniqs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", + "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=", + "dev": true + }, + "unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "requires": { + "crypto-random-string": "1.0.0" + } + }, + "units-css": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/units-css/-/units-css-0.4.0.tgz", + "integrity": "sha1-1iKGU6UZg9fBb/KPi53Dsf/tOgc=", + "dev": true, + "requires": { + "isnumeric": "0.2.0", + "viewport-dimensions": "0.2.0" + } + }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", + "dev": true + }, + "unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true + }, + "update-notifier": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.3.0.tgz", + "integrity": "sha1-TognpruRUUCrCTVZ1wFOPruDdFE=", + "dev": true, + "requires": { + "boxen": "1.2.2", + "chalk": "2.3.0", + "configstore": "3.1.1", + "import-lazy": "2.1.0", + "is-installed-globally": "0.1.0", + "is-npm": "1.0.0", + "latest-version": "3.1.0", + "semver-diff": "2.1.0", + "xdg-basedir": "3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.0" + } + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + } + } + }, + "url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "requires": { + "prepend-http": "1.0.4" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "vendors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", + "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + } + }, + "viewport-dimensions": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/viewport-dimensions/-/viewport-dimensions-0.2.0.tgz", + "integrity": "sha1-3nQHR9tTh/0XJfUXXpG6x2r982w=", + "dev": true + }, + "whet.extend": { + "version": "0.9.9", + "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", + "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=", + "dev": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "widest-line": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-1.0.0.tgz", + "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=", + "dev": true, + "requires": { + "string-width": "1.0.2" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "write-file-atomic": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.3.0.tgz", + "integrity": "sha512-xuPeK4OdjWqtfi59ylvVL0Yn35SF3zgcAcv7rBPFHVaEapaDr4GdGgm3j7ckTwH9wHL7fGmgfAnb0+THrHb8tA==", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "signal-exit": "3.0.2" + } + }, + "write-file-stdout": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/write-file-stdout/-/write-file-stdout-0.0.2.tgz", + "integrity": "sha1-wlLXx8WxtAKJdjDjRTx7/mkNnKE=", + "dev": true + }, + "xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "xxhashjs": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.1.tgz", + "integrity": "sha1-m76b6JYUKXbfo0wGGy0GjEPTDeA=", + "dev": true, + "requires": { + "cuint": "0.2.2" + } + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "dev": true, + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "dev": true, + "requires": { + "camelcase": "4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } + } + }, + "yauzl": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", + "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, + "requires": { + "fd-slicer": "1.0.1" + } + } + } +} diff --git a/library/cropperjs/package.json b/library/cropperjs/package.json new file mode 100644 index 000000000..f94100981 --- /dev/null +++ b/library/cropperjs/package.json @@ -0,0 +1,76 @@ +{ + "name": "cropperjs", + "description": "JavaScript image cropper.", + "version": "1.2.2", + "main": "dist/cropper.common.js", + "module": "dist/cropper.esm.js", + "browser": "dist/cropper.js", + "style": "dist/cropper.css", + "repository": "fengyuanchen/cropperjs", + "homepage": "https://fengyuanchen.github.io/cropperjs", + "license": "MIT", + "author": { + "name": "Chen Fengyuan", + "url": "http://chenfengyuan.com" + }, + "files": [ + "src", + "dist" + ], + "keywords": [ + "image", + "crop", + "cropping", + "move", + "zoom", + "rotate", + "scale", + "cropper", + "cropperjs", + "cropper.js", + "html", + "css", + "javascript", + "front-end", + "web", + "development" + ], + "scripts": { + "build": "npm run build:css && npm run build:js", + "build:css": "postcss src/css/cropper.css -o dist/cropper.css --no-map", + "build:js": "rollup -c", + "clear": "del-cli dist", + "compress": "npm run compress:css && npm run compress:js", + "compress:css": "postcss dist/cropper.css -u cssnano -o dist/cropper.min.css --no-map", + "compress:js": "uglifyjs dist/cropper.js -o dist/cropper.min.js -c -m --comments /^!/", + "copy": "cpy dist/cropper.css docs/css", + "lint": "eslint src/js --fix", + "release": "npm run clear && npm run lint && npm run build && npm run compress && npm run copy && npm test", + "start": "npm-run-all --parallel watch:*", + "test": "node-qunit-phantomjs test/index.html --timeout 10", + "watch:css": "postcss src/css/cropper.css -o docs/css/cropper.css -m -w", + "watch:js": "rollup -c -m -w" + }, + "devDependencies": { + "babel-core": "^6.26.0", + "babel-plugin-external-helpers": "^6.22.0", + "babel-preset-env": "^1.6.1", + "cpy-cli": "^1.0.1", + "cssnano": "^3.10.0", + "del-cli": "^1.1.0", + "eslint": "^4.14.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-import": "^2.8.0", + "node-qunit-phantomjs": "^2.0.0", + "npm-run-all": "^4.1.2", + "postcss-cli": "^4.1.1", + "postcss-cssnext": "^3.0.2", + "postcss-header": "^1.0.0", + "postcss-url": "^7.3.0", + "rollup": "^0.53.3", + "rollup-plugin-babel": "^3.0.3", + "rollup-watch": "^4.3.1", + "stylefmt": "^6.0.0", + "uglify-js": "^3.3.4" + } +} diff --git a/library/cropperjs/postcss.config.js b/library/cropperjs/postcss.config.js new file mode 100644 index 000000000..af7ec6024 --- /dev/null +++ b/library/cropperjs/postcss.config.js @@ -0,0 +1,14 @@ +const rollupConfig = require('./rollup.config'); + +module.exports = { + plugins: { + 'postcss-cssnext': {}, + 'postcss-url': { + url: 'inline', + }, + 'postcss-header': { + header: rollupConfig.banner, + }, + stylefmt: {}, + }, +}; diff --git a/library/cropperjs/rollup.config.js b/library/cropperjs/rollup.config.js new file mode 100644 index 000000000..b792a79a7 --- /dev/null +++ b/library/cropperjs/rollup.config.js @@ -0,0 +1,50 @@ +const babel = require('rollup-plugin-babel'); +const pkg = require('./package'); + +const now = new Date(); +const banner = `/*! + * Cropper.js v${pkg.version} + * https://github.com/${pkg.repository} + * + * Copyright (c) 2015-${now.getFullYear()} ${pkg.author.name} + * Released under the ${pkg.license} license + * + * Date: ${now.toISOString()} + */ +`; + +module.exports = { + // Export banner for PostCSS + banner, + input: 'src/js/cropper.js', + output: [ + { + banner, + file: 'dist/cropper.js', + format: 'umd', + name: 'Cropper', + }, + { + banner, + file: 'dist/cropper.common.js', + format: 'cjs', + }, + { + banner, + file: 'dist/cropper.esm.js', + format: 'es', + }, + { + banner, + file: 'docs/js/cropper.js', + format: 'umd', + name: 'Cropper', + }, + ], + plugins: [ + babel({ + exclude: 'node_modules/**', + plugins: ['external-helpers'], + }), + ], +}; diff --git a/library/cropperjs/src/css/cropper.css b/library/cropperjs/src/css/cropper.css new file mode 100644 index 000000000..d09c4f182 --- /dev/null +++ b/library/cropperjs/src/css/cropper.css @@ -0,0 +1,290 @@ +:root { + --blue: #39f; +} + +.cropper-container { + direction: ltr; + font-size: 0; + line-height: 0; + position: relative; + touch-action: none; + user-select: none; + + & img { + /* Avoid margin top issue (Occur only when margin-top <= -height) */ + display: block; + height: 100%; + image-orientation: 0deg; + max-height: none !important; + max-width: none !important; + min-height: 0 !important; + min-width: 0 !important; + width: 100%; + } +} + +.cropper-wrap-box, +.cropper-canvas, +.cropper-drag-box, +.cropper-crop-box, +.cropper-modal { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.cropper-wrap-box, +.cropper-canvas { + overflow: hidden; +} + +.cropper-drag-box { + background-color: #fff; + opacity: 0; +} + +.cropper-modal { + background-color: #000; + opacity: .5; +} + +.cropper-view-box { + display: block; + height: 100%; + outline-color: color(var(--blue) alpha(75%)); + outline: 1px solid var(--blue); + overflow: hidden; + width: 100%; +} + +.cropper-dashed { + border: 0 dashed #eee; + display: block; + opacity: .5; + position: absolute; + + &.dashed-h { + border-bottom-width: 1px; + border-top-width: 1px; + height: calc(100 / 3)%; + left: 0; + top: calc(100 / 3)%; + width: 100%; + } + + &.dashed-v { + border-left-width: 1px; + border-right-width: 1px; + height: 100%; + left: calc(100 / 3)%; + top: 0; + width: calc(100 / 3)%; + } +} + +.cropper-center { + display: block; + height: 0; + left: 50%; + opacity: .75; + position: absolute; + top: 50%; + width: 0; + + &:before, + &:after { + background-color: #eee; + content: ' '; + display: block; + position: absolute; + } + + &:before { + height: 1px; + left: -3px; + top: 0; + width: 7px; + } + + &:after { + height: 7px; + left: 0; + top: -3px; + width: 1px; + } +} + +.cropper-face, +.cropper-line, +.cropper-point { + display: block; + height: 100%; + opacity: .1; + position: absolute; + width: 100%; +} + +.cropper-face { + background-color: #fff; + left: 0; + top: 0; +} + +.cropper-line { + background-color: var(--blue); + + &.line-e { + cursor: ew-resize; + right: -3px; + top: 0; + width: 5px; + } + + &.line-n { + cursor: ns-resize; + height: 5px; + left: 0; + top: -3px; + } + + &.line-w { + cursor: ew-resize; + left: -3px; + top: 0; + width: 5px; + } + + &.line-s { + bottom: -3px; + cursor: ns-resize; + height: 5px; + left: 0; + } +} + +.cropper-point { + background-color: var(--blue); + height: 5px; + opacity: .75; + width: 5px; + + &.point-e { + cursor: ew-resize; + margin-top: -3px; + right: -3px; + top: 50%; + } + + &.point-n { + cursor: ns-resize; + left: 50%; + margin-left: -3px; + top: -3px; + } + + &.point-w { + cursor: ew-resize; + left: -3px; + margin-top: -3px; + top: 50%; + } + + &.point-s { + bottom: -3px; + cursor: s-resize; + left: 50%; + margin-left: -3px; + } + + &.point-ne { + cursor: nesw-resize; + right: -3px; + top: -3px; + } + + &.point-nw { + cursor: nwse-resize; + left: -3px; + top: -3px; + } + + &.point-sw { + bottom: -3px; + cursor: nesw-resize; + left: -3px; + } + + &.point-se { + bottom: -3px; + cursor: nwse-resize; + height: 20px; + opacity: 1; + right: -3px; + width: 20px; + + @media (min-width: 768px) { + height: 15px; + width: 15px; + } + + @media (min-width: 992px) { + height: 10px; + width: 10px; + } + + @media (min-width: 1200px) { + height: 5px; + opacity: .75; + width: 5px; + } + } + + &.point-se:before { + background-color: var(--blue); + bottom: -50%; + content: ' '; + display: block; + height: 200%; + opacity: 0; + position: absolute; + right: -50%; + width: 200%; + } +} + +.cropper-invisible { + opacity: 0; +} + +.cropper-bg { + background-image: url('../images/bg.png'); +} + +.cropper-hide { + display: block; + height: 0; + position: absolute; + width: 0; +} + +.cropper-hidden { + display: none !important; +} + +.cropper-move { + cursor: move; +} + +.cropper-crop { + cursor: crosshair; +} + +.cropper-disabled .cropper-drag-box, +.cropper-disabled .cropper-face, +.cropper-disabled .cropper-line, +.cropper-disabled .cropper-point { + cursor: not-allowed; +} + diff --git a/library/cropperjs/src/images/bg.png b/library/cropperjs/src/images/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..3c7056b1940609526bd3091a82fb3b5af37a16cd GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!D3?x-;bCrM;bFq_W2nPqp?T7vkfLyi!pAgqG zXU_cp|NnBYXcbP0 Hl+XkKKtwUY literal 0 HcmV?d00001 diff --git a/library/cropperjs/src/js/change.js b/library/cropperjs/src/js/change.js new file mode 100644 index 000000000..014222ef0 --- /dev/null +++ b/library/cropperjs/src/js/change.js @@ -0,0 +1,471 @@ +import { + ACTION_ALL, + ACTION_CROP, + ACTION_EAST, + ACTION_MOVE, + ACTION_NORTH, + ACTION_NORTH_EAST, + ACTION_NORTH_WEST, + ACTION_SOUTH, + ACTION_SOUTH_EAST, + ACTION_SOUTH_WEST, + ACTION_WEST, + ACTION_ZOOM, + CLASS_HIDDEN, +} from './constants'; +import { + each, + getMaxZoomRatio, + getOffset, + removeClass, +} from './utilities'; + +export default { + change(e) { + const { + options, + canvasData, + containerData, + cropBoxData, + pointers, + } = this; + let { action } = this; + let { aspectRatio } = options; + let { + left, + top, + width, + height, + } = cropBoxData; + const right = left + width; + const bottom = top + height; + let minLeft = 0; + let minTop = 0; + let maxWidth = containerData.width; + let maxHeight = containerData.height; + let renderable = true; + let offset; + + // Locking aspect ratio in "free mode" by holding shift key + if (!aspectRatio && e.shiftKey) { + aspectRatio = width && height ? width / height : 1; + } + + if (this.limited) { + ({ minLeft, minTop } = cropBoxData); + maxWidth = minLeft + Math.min( + containerData.width, + canvasData.width, + canvasData.left + canvasData.width, + ); + maxHeight = minTop + Math.min( + containerData.height, + canvasData.height, + canvasData.top + canvasData.height, + ); + } + + const pointer = pointers[Object.keys(pointers)[0]]; + const range = { + x: pointer.endX - pointer.startX, + y: pointer.endY - pointer.startY, + }; + const check = (side) => { + switch (side) { + case ACTION_EAST: + if (right + range.x > maxWidth) { + range.x = maxWidth - right; + } + + break; + + case ACTION_WEST: + if (left + range.x < minLeft) { + range.x = minLeft - left; + } + + break; + + case ACTION_NORTH: + if (top + range.y < minTop) { + range.y = minTop - top; + } + + break; + + case ACTION_SOUTH: + if (bottom + range.y > maxHeight) { + range.y = maxHeight - bottom; + } + + break; + + default: + } + }; + + switch (action) { + // Move crop box + case ACTION_ALL: + left += range.x; + top += range.y; + break; + + // Resize crop box + case ACTION_EAST: + if (range.x >= 0 && (right >= maxWidth || (aspectRatio && + (top <= minTop || bottom >= maxHeight)))) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top -= (range.x / aspectRatio) / 2; + } + + if (width < 0) { + action = ACTION_WEST; + width = 0; + } + + break; + + case ACTION_NORTH: + if (range.y <= 0 && (top <= minTop || (aspectRatio && + (left <= minLeft || right >= maxWidth)))) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left += (range.y * aspectRatio) / 2; + } + + if (height < 0) { + action = ACTION_SOUTH; + height = 0; + } + + break; + + case ACTION_WEST: + if (range.x <= 0 && (left <= minLeft || (aspectRatio && + (top <= minTop || bottom >= maxHeight)))) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + + if (aspectRatio) { + height = width / aspectRatio; + top += (range.x / aspectRatio) / 2; + } + + if (width < 0) { + action = ACTION_EAST; + width = 0; + } + + break; + + case ACTION_SOUTH: + if (range.y >= 0 && (bottom >= maxHeight || (aspectRatio && + (left <= minLeft || right >= maxWidth)))) { + renderable = false; + break; + } + + check(ACTION_SOUTH); + height += range.y; + + if (aspectRatio) { + width = height * aspectRatio; + left -= (range.y * aspectRatio) / 2; + } + + if (height < 0) { + action = ACTION_NORTH; + height = 0; + } + + break; + + case ACTION_NORTH_EAST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || right >= maxWidth)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + } + + break; + + case ACTION_NORTH_WEST: + if (aspectRatio) { + if (range.y <= 0 && (top <= minTop || left <= minLeft)) { + renderable = false; + break; + } + + check(ACTION_NORTH); + height -= range.y; + top += range.y; + width = height * aspectRatio; + left += range.y * aspectRatio; + } else { + check(ACTION_NORTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y <= 0 && top <= minTop) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y <= 0) { + if (top > minTop) { + height -= range.y; + top += range.y; + } + } else { + height -= range.y; + top += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_SOUTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_NORTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_SOUTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_WEST: + if (aspectRatio) { + if (range.x <= 0 && (left <= minLeft || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_WEST); + width -= range.x; + left += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_WEST); + + if (range.x <= 0) { + if (left > minLeft) { + width -= range.x; + left += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width -= range.x; + left += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_EAST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + } + + break; + + case ACTION_SOUTH_EAST: + if (aspectRatio) { + if (range.x >= 0 && (right >= maxWidth || bottom >= maxHeight)) { + renderable = false; + break; + } + + check(ACTION_EAST); + width += range.x; + height = width / aspectRatio; + } else { + check(ACTION_SOUTH); + check(ACTION_EAST); + + if (range.x >= 0) { + if (right < maxWidth) { + width += range.x; + } else if (range.y >= 0 && bottom >= maxHeight) { + renderable = false; + } + } else { + width += range.x; + } + + if (range.y >= 0) { + if (bottom < maxHeight) { + height += range.y; + } + } else { + height += range.y; + } + } + + if (width < 0 && height < 0) { + action = ACTION_NORTH_WEST; + height = 0; + width = 0; + } else if (width < 0) { + action = ACTION_SOUTH_WEST; + width = 0; + } else if (height < 0) { + action = ACTION_NORTH_EAST; + height = 0; + } + + break; + + // Move canvas + case ACTION_MOVE: + this.move(range.x, range.y); + renderable = false; + break; + + // Zoom canvas + case ACTION_ZOOM: + this.zoom(getMaxZoomRatio(pointers), e); + renderable = false; + break; + + // Create crop box + case ACTION_CROP: + if (!range.x || !range.y) { + renderable = false; + break; + } + + offset = getOffset(this.cropper); + left = pointer.startX - offset.left; + top = pointer.startY - offset.top; + width = cropBoxData.minWidth; + height = cropBoxData.minHeight; + + if (range.x > 0) { + action = range.y > 0 ? ACTION_SOUTH_EAST : ACTION_NORTH_EAST; + } else if (range.x < 0) { + left -= width; + action = range.y > 0 ? ACTION_SOUTH_WEST : ACTION_NORTH_WEST; + } + + if (range.y < 0) { + top -= height; + } + + // Show the crop box if is hidden + if (!this.cropped) { + removeClass(this.cropBox, CLASS_HIDDEN); + this.cropped = true; + + if (this.limited) { + this.limitCropBox(true, true); + } + } + + break; + + default: + } + + if (renderable) { + cropBoxData.width = width; + cropBoxData.height = height; + cropBoxData.left = left; + cropBoxData.top = top; + this.action = action; + this.renderCropBox(); + } + + // Override + each(pointers, (p) => { + p.startX = p.endX; + p.startY = p.endY; + }); + }, +}; diff --git a/library/cropperjs/src/js/constants.js b/library/cropperjs/src/js/constants.js new file mode 100644 index 000000000..c675d4d1c --- /dev/null +++ b/library/cropperjs/src/js/constants.js @@ -0,0 +1,56 @@ +export const WINDOW = typeof window !== 'undefined' ? window : {}; +export const NAMESPACE = 'cropper'; + +// Actions +export const ACTION_ALL = 'all'; +export const ACTION_CROP = 'crop'; +export const ACTION_MOVE = 'move'; +export const ACTION_ZOOM = 'zoom'; +export const ACTION_EAST = 'e'; +export const ACTION_WEST = 'w'; +export const ACTION_SOUTH = 's'; +export const ACTION_NORTH = 'n'; +export const ACTION_NORTH_EAST = 'ne'; +export const ACTION_NORTH_WEST = 'nw'; +export const ACTION_SOUTH_EAST = 'se'; +export const ACTION_SOUTH_WEST = 'sw'; + +// Classes +export const CLASS_CROP = `${NAMESPACE}-crop`; +export const CLASS_DISABLED = `${NAMESPACE}-disabled`; +export const CLASS_HIDDEN = `${NAMESPACE}-hidden`; +export const CLASS_HIDE = `${NAMESPACE}-hide`; +export const CLASS_INVISIBLE = `${NAMESPACE}-invisible`; +export const CLASS_MODAL = `${NAMESPACE}-modal`; +export const CLASS_MOVE = `${NAMESPACE}-move`; + +// Data keys +export const DATA_ACTION = 'action'; +export const DATA_PREVIEW = 'preview'; + +// Drag modes +export const DRAG_MODE_CROP = 'crop'; +export const DRAG_MODE_MOVE = 'move'; +export const DRAG_MODE_NONE = 'none'; + +// Events +export const EVENT_CROP = 'crop'; +export const EVENT_CROP_END = 'cropend'; +export const EVENT_CROP_MOVE = 'cropmove'; +export const EVENT_CROP_START = 'cropstart'; +export const EVENT_DBLCLICK = 'dblclick'; +export const EVENT_ERROR = 'error'; +export const EVENT_LOAD = 'load'; +export const EVENT_POINTER_DOWN = WINDOW.PointerEvent ? 'pointerdown' : 'touchstart mousedown'; +export const EVENT_POINTER_MOVE = WINDOW.PointerEvent ? 'pointermove' : 'touchmove mousemove'; +export const EVENT_POINTER_UP = WINDOW.PointerEvent ? 'pointerup pointercancel' : 'touchend touchcancel mouseup'; +export const EVENT_READY = 'ready'; +export const EVENT_RESIZE = 'resize'; +export const EVENT_WHEEL = 'wheel mousewheel DOMMouseScroll'; +export const EVENT_ZOOM = 'zoom'; + +// RegExps +export const REGEXP_ACTIONS = /^(?:e|w|s|n|se|sw|ne|nw|all|crop|move|zoom)$/; +export const REGEXP_DATA_URL = /^data:/; +export const REGEXP_DATA_URL_JPEG = /^data:image\/jpeg;base64,/; +export const REGEXP_TAG_NAME = /^(?:img|canvas)$/i; diff --git a/library/cropperjs/src/js/cropper.js b/library/cropperjs/src/js/cropper.js new file mode 100644 index 000000000..97f3511df --- /dev/null +++ b/library/cropperjs/src/js/cropper.js @@ -0,0 +1,421 @@ +import DEFAULTS from './defaults'; +import TEMPLATE from './template'; +import render from './render'; +import preview from './preview'; +import events from './events'; +import handlers from './handlers'; +import change from './change'; +import methods from './methods'; +import { + ACTION_ALL, + CLASS_HIDDEN, + CLASS_HIDE, + CLASS_INVISIBLE, + CLASS_MODAL, + CLASS_MOVE, + DATA_ACTION, + EVENT_CROP, + EVENT_ERROR, + EVENT_LOAD, + EVENT_READY, + NAMESPACE, + REGEXP_DATA_URL, + REGEXP_DATA_URL_JPEG, + REGEXP_TAG_NAME, + WINDOW, +} from './constants'; +import { + addClass, + addListener, + addTimestamp, + arrayBufferToDataURL, + dataURLToArrayBuffer, + dispatchEvent, + extend, + getData, + getImageNaturalSizes, + getOrientation, + isCrossOriginURL, + isFunction, + isPlainObject, + parseOrientation, + proxy, + removeClass, + removeListener, + setData, +} from './utilities'; + +const AnotherCropper = WINDOW.Cropper; + +class Cropper { + /** + * Create a new Cropper. + * @param {Element} element - The target element for cropping. + * @param {Object} [options={}] - The configuration options. + */ + constructor(element, options = {}) { + if (!element || !REGEXP_TAG_NAME.test(element.tagName)) { + throw new Error('The first argument is required and must be an or element.'); + } + + this.element = element; + this.options = extend({}, DEFAULTS, isPlainObject(options) && options); + this.complete = false; + this.cropped = false; + this.disabled = false; + this.isImg = false; + this.limited = false; + this.loaded = false; + this.ready = false; + this.replaced = false; + this.wheeling = false; + this.originalUrl = ''; + this.canvasData = null; + this.cropBoxData = null; + this.previews = null; + this.pointers = {}; + this.init(); + } + + init() { + const { element } = this; + const tagName = element.tagName.toLowerCase(); + let url; + + if (getData(element, NAMESPACE)) { + return; + } + + setData(element, NAMESPACE, this); + + if (tagName === 'img') { + this.isImg = true; + + // e.g.: "img/picture.jpg" + url = element.getAttribute('src') || ''; + this.originalUrl = url; + + // Stop when it's a blank image + if (!url) { + return; + } + + // e.g.: "http://example.com/img/picture.jpg" + url = element.src; + } else if (tagName === 'canvas' && window.HTMLCanvasElement) { + url = element.toDataURL(); + } + + this.load(url); + } + + load(url) { + if (!url) { + return; + } + + this.url = url; + this.imageData = {}; + + const { element, options } = this; + + if (!options.checkOrientation || !window.ArrayBuffer) { + this.clone(); + return; + } + + // XMLHttpRequest disallows to open a Data URL in some browsers like IE11 and Safari + if (REGEXP_DATA_URL.test(url)) { + if (REGEXP_DATA_URL_JPEG.test(url)) { + this.read(dataURLToArrayBuffer(url)); + } else { + this.clone(); + } + + return; + } + + const xhr = new XMLHttpRequest(); + + xhr.onerror = () => { + this.clone(); + }; + + xhr.onload = () => { + this.read(xhr.response); + }; + + // Bust cache when there is a "crossOrigin" property + if (options.checkCrossOrigin && isCrossOriginURL(url) && element.crossOrigin) { + url = addTimestamp(url); + } + + xhr.open('get', url); + xhr.responseType = 'arraybuffer'; + xhr.withCredentials = element.crossOrigin === 'use-credentials'; + xhr.send(); + } + + read(arrayBuffer) { + const { options, imageData } = this; + const orientation = getOrientation(arrayBuffer); + let rotate = 0; + let scaleX = 1; + let scaleY = 1; + + if (orientation > 1) { + this.url = arrayBufferToDataURL(arrayBuffer, 'image/jpeg'); + ({ rotate, scaleX, scaleY } = parseOrientation(orientation)); + } + + if (options.rotatable) { + imageData.rotate = rotate; + } + + if (options.scalable) { + imageData.scaleX = scaleX; + imageData.scaleY = scaleY; + } + + this.clone(); + } + + clone() { + const { element, url } = this; + let crossOrigin; + let crossOriginUrl; + + if (this.options.checkCrossOrigin && isCrossOriginURL(url)) { + ({ crossOrigin } = element); + + if (crossOrigin) { + crossOriginUrl = url; + } else { + crossOrigin = 'anonymous'; + + // Bust cache when there is not a "crossOrigin" property + crossOriginUrl = addTimestamp(url); + } + } + + this.crossOrigin = crossOrigin; + this.crossOriginUrl = crossOriginUrl; + + const image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = crossOriginUrl || url; + + const start = proxy(this.start, this); + const stop = proxy(this.stop, this); + + this.image = image; + this.onStart = start; + this.onStop = stop; + + if (this.isImg) { + if (element.complete) { + this.start(); + } else { + addListener(element, EVENT_LOAD, start); + } + } else { + addListener(image, EVENT_LOAD, start); + addListener(image, EVENT_ERROR, stop); + addClass(image, CLASS_HIDE); + element.parentNode.insertBefore(image, element.nextSibling); + } + } + + start(event) { + const image = this.isImg ? this.element : this.image; + + if (event) { + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + } + + getImageNaturalSizes(image, (naturalWidth, naturalHeight) => { + extend(this.imageData, { + naturalWidth, + naturalHeight, + aspectRatio: naturalWidth / naturalHeight, + }); + this.loaded = true; + this.build(); + }); + } + + stop() { + const { image } = this; + + removeListener(image, EVENT_LOAD, this.onStart); + removeListener(image, EVENT_ERROR, this.onStop); + image.parentNode.removeChild(image); + this.image = null; + } + + build() { + if (!this.loaded) { + return; + } + + // Unbuild first when replace + if (this.ready) { + this.unbuild(); + } + + const { element, options, image } = this; + + // Create cropper elements + const container = element.parentNode; + const template = document.createElement('div'); + + template.innerHTML = TEMPLATE; + + const cropper = template.querySelector(`.${NAMESPACE}-container`); + const canvas = cropper.querySelector(`.${NAMESPACE}-canvas`); + const dragBox = cropper.querySelector(`.${NAMESPACE}-drag-box`); + const cropBox = cropper.querySelector(`.${NAMESPACE}-crop-box`); + const face = cropBox.querySelector(`.${NAMESPACE}-face`); + + this.container = container; + this.cropper = cropper; + this.canvas = canvas; + this.dragBox = dragBox; + this.cropBox = cropBox; + this.viewBox = cropper.querySelector(`.${NAMESPACE}-view-box`); + this.face = face; + + canvas.appendChild(image); + + // Hide the original image + addClass(element, CLASS_HIDDEN); + + // Inserts the cropper after to the current image + container.insertBefore(cropper, element.nextSibling); + + // Show the image if is hidden + if (!this.isImg) { + removeClass(image, CLASS_HIDE); + } + + this.initPreview(); + this.bind(); + + options.aspectRatio = Math.max(0, options.aspectRatio) || NaN; + options.viewMode = Math.max(0, Math.min(3, Math.round(options.viewMode))) || 0; + + this.cropped = options.autoCrop; + + if (options.autoCrop) { + if (options.modal) { + addClass(dragBox, CLASS_MODAL); + } + } else { + addClass(cropBox, CLASS_HIDDEN); + } + + if (!options.guides) { + addClass(cropBox.getElementsByClassName(`${NAMESPACE}-dashed`), CLASS_HIDDEN); + } + + if (!options.center) { + addClass(cropBox.getElementsByClassName(`${NAMESPACE}-center`), CLASS_HIDDEN); + } + + if (options.background) { + addClass(cropper, `${NAMESPACE}-bg`); + } + + if (!options.highlight) { + addClass(face, CLASS_INVISIBLE); + } + + if (options.cropBoxMovable) { + addClass(face, CLASS_MOVE); + setData(face, DATA_ACTION, ACTION_ALL); + } + + if (!options.cropBoxResizable) { + addClass(cropBox.getElementsByClassName(`${NAMESPACE}-line`), CLASS_HIDDEN); + addClass(cropBox.getElementsByClassName(`${NAMESPACE}-point`), CLASS_HIDDEN); + } + + this.setDragMode(options.dragMode); + this.render(); + this.ready = true; + this.setData(options.data); + + // Call the "ready" option asynchronously to keep "image.cropper" is defined + this.completing = setTimeout(() => { + if (isFunction(options.ready)) { + addListener(element, EVENT_READY, options.ready, { + once: true, + }); + } + + dispatchEvent(element, EVENT_READY); + dispatchEvent(element, EVENT_CROP, this.getData()); + + this.complete = true; + }, 0); + } + + unbuild() { + if (!this.ready) { + return; + } + + if (!this.complete) { + clearTimeout(this.completing); + } + + this.ready = false; + this.complete = false; + this.initialImageData = null; + + // Clear `initialCanvasData` is necessary when replace + this.initialCanvasData = null; + this.initialCropBoxData = null; + this.containerData = null; + this.canvasData = null; + + // Clear `cropBoxData` is necessary when replace + this.cropBoxData = null; + this.unbind(); + this.resetPreview(); + this.previews = null; + this.viewBox = null; + this.cropBox = null; + this.dragBox = null; + this.canvas = null; + this.container = null; + this.cropper.parentNode.removeChild(this.cropper); + this.cropper = null; + } + + /** + * Get the no conflict cropper class. + * @returns {Cropper} The cropper class. + */ + static noConflict() { + window.Cropper = AnotherCropper; + return Cropper; + } + + /** + * Change the default options. + * @param {Object} options - The new default options. + */ + static setDefaults(options) { + extend(DEFAULTS, isPlainObject(options) && options); + } +} + +extend(Cropper.prototype, render, preview, events, handlers, change, methods); + +export default Cropper; diff --git a/library/cropperjs/src/js/defaults.js b/library/cropperjs/src/js/defaults.js new file mode 100644 index 000000000..aa469e73a --- /dev/null +++ b/library/cropperjs/src/js/defaults.js @@ -0,0 +1,99 @@ +import { + DRAG_MODE_CROP, +} from './constants'; + +export default { + // Define the view mode of the cropper + viewMode: 0, // 0, 1, 2, 3 + + // Define the dragging mode of the cropper + dragMode: DRAG_MODE_CROP, // 'crop', 'move' or 'none' + + // Define the aspect ratio of the crop box + aspectRatio: NaN, + + // An object with the previous cropping result data + data: null, + + // A selector for adding extra containers to preview + preview: '', + + // Re-render the cropper when resize the window + responsive: true, + + // Restore the cropped area after resize the window + restore: true, + + // Check if the current image is a cross-origin image + checkCrossOrigin: true, + + // Check the current image's Exif Orientation information + checkOrientation: true, + + // Show the black modal + modal: true, + + // Show the dashed lines for guiding + guides: true, + + // Show the center indicator for guiding + center: true, + + // Show the white modal to highlight the crop box + highlight: true, + + // Show the grid background + background: true, + + // Enable to crop the image automatically when initialize + autoCrop: true, + + // Define the percentage of automatic cropping area when initializes + autoCropArea: 0.8, + + // Enable to move the image + movable: true, + + // Enable to rotate the image + rotatable: true, + + // Enable to scale the image + scalable: true, + + // Enable to zoom the image + zoomable: true, + + // Enable to zoom the image by dragging touch + zoomOnTouch: true, + + // Enable to zoom the image by wheeling mouse + zoomOnWheel: true, + + // Define zoom ratio when zoom the image by wheeling mouse + wheelZoomRatio: 0.1, + + // Enable to move the crop box + cropBoxMovable: true, + + // Enable to resize the crop box + cropBoxResizable: true, + + // Toggle drag mode between "crop" and "move" when click twice on the cropper + toggleDragModeOnDblclick: true, + + // Size limitation + minCanvasWidth: 0, + minCanvasHeight: 0, + minCropBoxWidth: 0, + minCropBoxHeight: 0, + minContainerWidth: 200, + minContainerHeight: 100, + + // Shortcuts of events + ready: null, + cropstart: null, + cropmove: null, + cropend: null, + crop: null, + zoom: null, +}; diff --git a/library/cropperjs/src/js/events.js b/library/cropperjs/src/js/events.js new file mode 100644 index 000000000..3753db022 --- /dev/null +++ b/library/cropperjs/src/js/events.js @@ -0,0 +1,111 @@ +import { + EVENT_CROP, + EVENT_CROP_END, + EVENT_CROP_MOVE, + EVENT_CROP_START, + EVENT_DBLCLICK, + EVENT_POINTER_DOWN, + EVENT_POINTER_MOVE, + EVENT_POINTER_UP, + EVENT_RESIZE, + EVENT_WHEEL, + EVENT_ZOOM, +} from './constants'; +import { + addListener, + isFunction, + proxy, + removeListener, +} from './utilities'; + +export default { + bind() { + const { element, options, cropper } = this; + + if (isFunction(options.cropstart)) { + addListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + addListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + addListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + addListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + addListener(element, EVENT_ZOOM, options.zoom); + } + + addListener(cropper, EVENT_POINTER_DOWN, (this.onCropStart = proxy(this.cropStart, this))); + + if (options.zoomable && options.zoomOnWheel) { + addListener(cropper, EVENT_WHEEL, (this.onWheel = proxy(this.wheel, this))); + } + + if (options.toggleDragModeOnDblclick) { + addListener(cropper, EVENT_DBLCLICK, (this.onDblclick = proxy(this.dblclick, this))); + } + + addListener( + element.ownerDocument, + EVENT_POINTER_MOVE, + (this.onCropMove = proxy(this.cropMove, this)), + ); + addListener( + element.ownerDocument, + EVENT_POINTER_UP, + (this.onCropEnd = proxy(this.cropEnd, this)), + ); + + if (options.responsive) { + addListener(window, EVENT_RESIZE, (this.onResize = proxy(this.resize, this))); + } + }, + + unbind() { + const { element, options, cropper } = this; + + if (isFunction(options.cropstart)) { + removeListener(element, EVENT_CROP_START, options.cropstart); + } + + if (isFunction(options.cropmove)) { + removeListener(element, EVENT_CROP_MOVE, options.cropmove); + } + + if (isFunction(options.cropend)) { + removeListener(element, EVENT_CROP_END, options.cropend); + } + + if (isFunction(options.crop)) { + removeListener(element, EVENT_CROP, options.crop); + } + + if (isFunction(options.zoom)) { + removeListener(element, EVENT_ZOOM, options.zoom); + } + + removeListener(cropper, EVENT_POINTER_DOWN, this.onCropStart); + + if (options.zoomable && options.zoomOnWheel) { + removeListener(cropper, EVENT_WHEEL, this.onWheel); + } + + if (options.toggleDragModeOnDblclick) { + removeListener(cropper, EVENT_DBLCLICK, this.onDblclick); + } + + removeListener(element.ownerDocument, EVENT_POINTER_MOVE, this.onCropMove); + removeListener(element.ownerDocument, EVENT_POINTER_UP, this.onCropEnd); + + if (options.responsive) { + removeListener(window, EVENT_RESIZE, this.onResize); + } + }, +}; diff --git a/library/cropperjs/src/js/handlers.js b/library/cropperjs/src/js/handlers.js new file mode 100644 index 000000000..7b7b2469a --- /dev/null +++ b/library/cropperjs/src/js/handlers.js @@ -0,0 +1,212 @@ +import { + ACTION_CROP, + ACTION_ZOOM, + CLASS_CROP, + CLASS_MODAL, + DATA_ACTION, + DRAG_MODE_CROP, + DRAG_MODE_MOVE, + DRAG_MODE_NONE, + EVENT_CROP_END, + EVENT_CROP_MOVE, + EVENT_CROP_START, + REGEXP_ACTIONS, +} from './constants'; +import { + addClass, + dispatchEvent, + each, + extend, + getData, + getPointer, + hasClass, + toggleClass, +} from './utilities'; + +export default { + resize() { + const { options, container, containerData } = this; + const minContainerWidth = Number(options.minContainerWidth) || 200; + const minContainerHeight = Number(options.minContainerHeight) || 100; + + if (this.disabled || containerData.width <= minContainerWidth || + containerData.height <= minContainerHeight) { + return; + } + + const ratio = container.offsetWidth / containerData.width; + + // Resize when width changed or height changed + if (ratio !== 1 || container.offsetHeight !== containerData.height) { + let canvasData; + let cropBoxData; + + if (options.restore) { + canvasData = this.getCanvasData(); + cropBoxData = this.getCropBoxData(); + } + + this.render(); + + if (options.restore) { + this.setCanvasData(each(canvasData, (n, i) => { + canvasData[i] = n * ratio; + })); + this.setCropBoxData(each(cropBoxData, (n, i) => { + cropBoxData[i] = n * ratio; + })); + } + } + }, + + dblclick() { + if (this.disabled || this.options.dragMode === DRAG_MODE_NONE) { + return; + } + + this.setDragMode(hasClass(this.dragBox, CLASS_CROP) ? DRAG_MODE_MOVE : DRAG_MODE_CROP); + }, + + wheel(e) { + const ratio = Number(this.options.wheelZoomRatio) || 0.1; + let delta = 1; + + if (this.disabled) { + return; + } + + e.preventDefault(); + + // Limit wheel speed to prevent zoom too fast (#21) + if (this.wheeling) { + return; + } + + this.wheeling = true; + + setTimeout(() => { + this.wheeling = false; + }, 50); + + if (e.deltaY) { + delta = e.deltaY > 0 ? 1 : -1; + } else if (e.wheelDelta) { + delta = -e.wheelDelta / 120; + } else if (e.detail) { + delta = e.detail > 0 ? 1 : -1; + } + + this.zoom(-delta * ratio, e); + }, + + cropStart(e) { + if (this.disabled) { + return; + } + + const { options, pointers } = this; + let action; + + if (e.changedTouches) { + // Handle touch event + each(e.changedTouches, (touch) => { + pointers[touch.identifier] = getPointer(touch); + }); + } else { + // Handle mouse event and pointer event + pointers[e.pointerId || 0] = getPointer(e); + } + + if (Object.keys(pointers).length > 1 && options.zoomable && options.zoomOnTouch) { + action = ACTION_ZOOM; + } else { + action = getData(e.target, DATA_ACTION); + } + + if (!REGEXP_ACTIONS.test(action)) { + return; + } + + if (dispatchEvent(this.element, EVENT_CROP_START, { + originalEvent: e, + action, + }) === false) { + return; + } + + e.preventDefault(); + + this.action = action; + this.cropping = false; + + if (action === ACTION_CROP) { + this.cropping = true; + addClass(this.dragBox, CLASS_MODAL); + } + }, + + cropMove(e) { + const { action } = this; + + if (this.disabled || !action) { + return; + } + + const { pointers } = this; + + e.preventDefault(); + + if (dispatchEvent(this.element, EVENT_CROP_MOVE, { + originalEvent: e, + action, + }) === false) { + return; + } + + if (e.changedTouches) { + each(e.changedTouches, (touch) => { + extend(pointers[touch.identifier], getPointer(touch, true)); + }); + } else { + extend(pointers[e.pointerId || 0], getPointer(e, true)); + } + + this.change(e); + }, + + cropEnd(e) { + if (this.disabled) { + return; + } + + const { action, pointers } = this; + + if (e.changedTouches) { + each(e.changedTouches, (touch) => { + delete pointers[touch.identifier]; + }); + } else { + delete pointers[e.pointerId || 0]; + } + + if (!action) { + return; + } + + e.preventDefault(); + + if (!Object.keys(pointers).length) { + this.action = ''; + } + + if (this.cropping) { + this.cropping = false; + toggleClass(this.dragBox, CLASS_MODAL, this.cropped && this.options.modal); + } + + dispatchEvent(this.element, EVENT_CROP_END, { + originalEvent: e, + action, + }); + }, +}; diff --git a/library/cropperjs/src/js/methods.js b/library/cropperjs/src/js/methods.js new file mode 100644 index 000000000..3627d2bd1 --- /dev/null +++ b/library/cropperjs/src/js/methods.js @@ -0,0 +1,842 @@ +import { + CLASS_CROP, + CLASS_DISABLED, + CLASS_HIDDEN, + CLASS_MODAL, + CLASS_MOVE, + DATA_ACTION, + DRAG_MODE_CROP, + DRAG_MODE_MOVE, + DRAG_MODE_NONE, + EVENT_LOAD, + EVENT_ZOOM, + NAMESPACE, +} from './constants'; +import { + addClass, + dispatchEvent, + each, + extend, + getAdjustedSizes, + getOffset, + getPointersCenter, + getSourceCanvas, + isFunction, + isNumber, + isPlainObject, + isUndefined, + normalizeDecimalNumber, + removeClass, + removeData, + removeListener, + setData, + toggleClass, +} from './utilities'; + +export default { + // Show the crop box manually + crop() { + if (this.ready && !this.disabled) { + if (!this.cropped) { + this.cropped = true; + this.limitCropBox(true, true); + + if (this.options.modal) { + addClass(this.dragBox, CLASS_MODAL); + } + + removeClass(this.cropBox, CLASS_HIDDEN); + } + + this.setCropBoxData(this.initialCropBoxData); + } + + return this; + }, + + // Reset the image and crop box to their initial states + reset() { + if (this.ready && !this.disabled) { + this.imageData = extend({}, this.initialImageData); + this.canvasData = extend({}, this.initialCanvasData); + this.cropBoxData = extend({}, this.initialCropBoxData); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + } + + return this; + }, + + // Clear the crop box + clear() { + if (this.cropped && !this.disabled) { + extend(this.cropBoxData, { + left: 0, + top: 0, + width: 0, + height: 0, + }); + + this.cropped = false; + this.renderCropBox(); + this.limitCanvas(true, true); + + // Render canvas after crop box rendered + this.renderCanvas(); + removeClass(this.dragBox, CLASS_MODAL); + addClass(this.cropBox, CLASS_HIDDEN); + } + + return this; + }, + + /** + * Replace the image's src and rebuild the cropper + * @param {string} url - The new URL. + * @param {boolean} [onlyColorChanged] - Indicate if the new image only changed color. + * @returns {Object} this + */ + replace(url, onlyColorChanged = false) { + if (!this.disabled && url) { + if (this.isImg) { + this.element.src = url; + } + + if (onlyColorChanged) { + this.url = url; + this.image.src = url; + + if (this.ready) { + this.image2.src = url; + + each(this.previews, (element) => { + element.getElementsByTagName('img')[0].src = url; + }); + } + } else { + if (this.isImg) { + this.replaced = true; + } + + // Clear previous data + this.options.data = null; + this.load(url); + } + } + + return this; + }, + + // Enable (unfreeze) the cropper + enable() { + if (this.ready) { + this.disabled = false; + removeClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + // Disable (freeze) the cropper + disable() { + if (this.ready) { + this.disabled = true; + addClass(this.cropper, CLASS_DISABLED); + } + + return this; + }, + + // Destroy the cropper and remove the instance from the image + destroy() { + const { element, image } = this; + + if (this.loaded) { + if (this.isImg && this.replaced) { + element.src = this.originalUrl; + } + + this.unbuild(); + removeClass(element, CLASS_HIDDEN); + } else if (this.isImg) { + removeListener(element, EVENT_LOAD, this.onStart); + } else if (image) { + image.parentNode.removeChild(image); + } + + removeData(element, NAMESPACE); + + return this; + }, + + /** + * Move the canvas with relative offsets + * @param {number} offsetX - The relative offset distance on the x-axis. + * @param {number} offsetY - The relative offset distance on the y-axis. + * @returns {Object} this + */ + move(offsetX, offsetY) { + const { left, top } = this.canvasData; + + return this.moveTo( + isUndefined(offsetX) ? offsetX : (left + Number(offsetX)), + isUndefined(offsetY) ? offsetY : (top + Number(offsetY)), + ); + }, + + /** + * Move the canvas to an absolute point + * @param {number} x - The x-axis coordinate. + * @param {number} [y=x] - The y-axis coordinate. + * @returns {Object} this + */ + moveTo(x, y = x) { + const { canvasData } = this; + let changed = false; + + x = Number(x); + y = Number(y); + + if (this.ready && !this.disabled && this.options.movable) { + if (isNumber(x)) { + canvasData.left = x; + changed = true; + } + + if (isNumber(y)) { + canvasData.top = y; + changed = true; + } + + if (changed) { + this.renderCanvas(true); + } + } + + return this; + }, + + /** + * Zoom the canvas with a relative ratio + * @param {number} ratio - The target ratio. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoom(ratio, _originalEvent) { + const { canvasData } = this; + + ratio = Number(ratio); + + if (ratio < 0) { + ratio = 1 / (1 - ratio); + } else { + ratio = 1 + ratio; + } + + return this.zoomTo((canvasData.width * ratio) / canvasData.naturalWidth, null, _originalEvent); + }, + + /** + * Zoom the canvas to an absolute ratio + * @param {number} ratio - The target ratio. + * @param {Object} pivot - The zoom pivot point coordinate. + * @param {Event} _originalEvent - The original event if any. + * @returns {Object} this + */ + zoomTo(ratio, pivot, _originalEvent) { + const { options, canvasData } = this; + const { + width, + height, + naturalWidth, + naturalHeight, + } = canvasData; + + ratio = Number(ratio); + + if (ratio >= 0 && this.ready && !this.disabled && options.zoomable) { + const newWidth = naturalWidth * ratio; + const newHeight = naturalHeight * ratio; + + if (dispatchEvent(this.element, EVENT_ZOOM, { + originalEvent: _originalEvent, + oldRatio: width / naturalWidth, + ratio: newWidth / naturalWidth, + }) === false) { + return this; + } + + if (_originalEvent) { + const { pointers } = this; + const offset = getOffset(this.cropper); + const center = pointers && Object.keys(pointers).length ? getPointersCenter(pointers) : { + pageX: _originalEvent.pageX, + pageY: _originalEvent.pageY, + }; + + // Zoom from the triggering point of the event + canvasData.left -= (newWidth - width) * ( + ((center.pageX - offset.left) - canvasData.left) / width + ); + canvasData.top -= (newHeight - height) * ( + ((center.pageY - offset.top) - canvasData.top) / height + ); + } else if (isPlainObject(pivot) && isNumber(pivot.x) && isNumber(pivot.y)) { + canvasData.left -= (newWidth - width) * ( + (pivot.x - canvasData.left) / width + ); + canvasData.top -= (newHeight - height) * ( + (pivot.y - canvasData.top) / height + ); + } else { + // Zoom from the center of the canvas + canvasData.left -= (newWidth - width) / 2; + canvasData.top -= (newHeight - height) / 2; + } + + canvasData.width = newWidth; + canvasData.height = newHeight; + this.renderCanvas(true); + } + + return this; + }, + + /** + * Rotate the canvas with a relative degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotate(degree) { + return this.rotateTo((this.imageData.rotate || 0) + Number(degree)); + }, + + /** + * Rotate the canvas to an absolute degree + * @param {number} degree - The rotate degree. + * @returns {Object} this + */ + rotateTo(degree) { + degree = Number(degree); + + if (isNumber(degree) && this.ready && !this.disabled && this.options.rotatable) { + this.imageData.rotate = degree % 360; + this.renderCanvas(true, true); + } + + return this; + }, + + /** + * Scale the image on the x-axis. + * @param {number} scaleX - The scale ratio on the x-axis. + * @returns {Object} this + */ + scaleX(scaleX) { + const { scaleY } = this.imageData; + + return this.scale(scaleX, isNumber(scaleY) ? scaleY : 1); + }, + + /** + * Scale the image on the y-axis. + * @param {number} scaleY - The scale ratio on the y-axis. + * @returns {Object} this + */ + scaleY(scaleY) { + const { scaleX } = this.imageData; + + return this.scale(isNumber(scaleX) ? scaleX : 1, scaleY); + }, + + /** + * Scale the image + * @param {number} scaleX - The scale ratio on the x-axis. + * @param {number} [scaleY=scaleX] - The scale ratio on the y-axis. + * @returns {Object} this + */ + scale(scaleX, scaleY = scaleX) { + const { imageData } = this; + let transformed = false; + + scaleX = Number(scaleX); + scaleY = Number(scaleY); + + if (this.ready && !this.disabled && this.options.scalable) { + if (isNumber(scaleX)) { + imageData.scaleX = scaleX; + transformed = true; + } + + if (isNumber(scaleY)) { + imageData.scaleY = scaleY; + transformed = true; + } + + if (transformed) { + this.renderCanvas(true, true); + } + } + + return this; + }, + + /** + * Get the cropped area position and size data (base on the original image) + * @param {boolean} [rounded=false] - Indicate if round the data values or not. + * @returns {Object} The result cropped data. + */ + getData(rounded = false) { + const { + options, + imageData, + canvasData, + cropBoxData, + } = this; + let data; + + if (this.ready && this.cropped) { + data = { + x: cropBoxData.left - canvasData.left, + y: cropBoxData.top - canvasData.top, + width: cropBoxData.width, + height: cropBoxData.height, + }; + + const ratio = imageData.width / imageData.naturalWidth; + + each(data, (n, i) => { + n /= ratio; + data[i] = rounded ? Math.round(n) : n; + }); + } else { + data = { + x: 0, + y: 0, + width: 0, + height: 0, + }; + } + + if (options.rotatable) { + data.rotate = imageData.rotate || 0; + } + + if (options.scalable) { + data.scaleX = imageData.scaleX || 1; + data.scaleY = imageData.scaleY || 1; + } + + return data; + }, + + /** + * Set the cropped area position and size with new data + * @param {Object} data - The new data. + * @returns {Object} this + */ + setData(data) { + const { options, imageData, canvasData } = this; + const cropBoxData = {}; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + let transformed = false; + + if (options.rotatable) { + if (isNumber(data.rotate) && data.rotate !== imageData.rotate) { + imageData.rotate = data.rotate; + transformed = true; + } + } + + if (options.scalable) { + if (isNumber(data.scaleX) && data.scaleX !== imageData.scaleX) { + imageData.scaleX = data.scaleX; + transformed = true; + } + + if (isNumber(data.scaleY) && data.scaleY !== imageData.scaleY) { + imageData.scaleY = data.scaleY; + transformed = true; + } + } + + if (transformed) { + this.renderCanvas(true, true); + } + + const ratio = imageData.width / imageData.naturalWidth; + + if (isNumber(data.x)) { + cropBoxData.left = (data.x * ratio) + canvasData.left; + } + + if (isNumber(data.y)) { + cropBoxData.top = (data.y * ratio) + canvasData.top; + } + + if (isNumber(data.width)) { + cropBoxData.width = data.width * ratio; + } + + if (isNumber(data.height)) { + cropBoxData.height = data.height * ratio; + } + + this.setCropBoxData(cropBoxData); + } + + return this; + }, + + /** + * Get the container size data. + * @returns {Object} The result container data. + */ + getContainerData() { + return this.ready ? extend({}, this.containerData) : {}; + }, + + /** + * Get the image position and size data. + * @returns {Object} The result image data. + */ + getImageData() { + return this.loaded ? extend({}, this.imageData) : {}; + }, + + /** + * Get the canvas position and size data. + * @returns {Object} The result canvas data. + */ + getCanvasData() { + const { canvasData } = this; + const data = {}; + + if (this.ready) { + each([ + 'left', + 'top', + 'width', + 'height', + 'naturalWidth', + 'naturalHeight', + ], (n) => { + data[n] = canvasData[n]; + }); + } + + return data; + }, + + /** + * Set the canvas position and size with new data. + * @param {Object} data - The new canvas data. + * @returns {Object} this + */ + setCanvasData(data) { + const { canvasData } = this; + const { aspectRatio } = canvasData; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + canvasData.left = data.left; + } + + if (isNumber(data.top)) { + canvasData.top = data.top; + } + + if (isNumber(data.width)) { + canvasData.width = data.width; + canvasData.height = data.width / aspectRatio; + } else if (isNumber(data.height)) { + canvasData.height = data.height; + canvasData.width = data.height * aspectRatio; + } + + this.renderCanvas(true); + } + + return this; + }, + + /** + * Get the crop box position and size data. + * @returns {Object} The result crop box data. + */ + getCropBoxData() { + const { cropBoxData } = this; + let data; + + if (this.ready && this.cropped) { + data = { + left: cropBoxData.left, + top: cropBoxData.top, + width: cropBoxData.width, + height: cropBoxData.height, + }; + } + + return data || {}; + }, + + /** + * Set the crop box position and size with new data. + * @param {Object} data - The new crop box data. + * @returns {Object} this + */ + setCropBoxData(data) { + const { cropBoxData } = this; + const { aspectRatio } = this.options; + let widthChanged; + let heightChanged; + + if (isFunction(data)) { + data = data.call(this.element); + } + + if (this.ready && this.cropped && !this.disabled && isPlainObject(data)) { + if (isNumber(data.left)) { + cropBoxData.left = data.left; + } + + if (isNumber(data.top)) { + cropBoxData.top = data.top; + } + + if (isNumber(data.width) && data.width !== cropBoxData.width) { + widthChanged = true; + cropBoxData.width = data.width; + } + + if (isNumber(data.height) && data.height !== cropBoxData.height) { + heightChanged = true; + cropBoxData.height = data.height; + } + + if (aspectRatio) { + if (widthChanged) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else if (heightChanged) { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.renderCropBox(); + } + + return this; + }, + + /** + * Get a canvas drawn the cropped image. + * @param {Object} [options={}] - The config options. + * @returns {HTMLCanvasElement} - The result canvas. + */ + getCroppedCanvas(options = {}) { + if (!this.ready || !window.HTMLCanvasElement) { + return null; + } + + const { canvasData } = this; + const source = getSourceCanvas(this.image, this.imageData, canvasData, options); + + // Returns the source canvas if it is not cropped. + if (!this.cropped) { + return source; + } + + let { + x: initialX, + y: initialY, + width: initialWidth, + height: initialHeight, + } = this.getData(); + const ratio = source.width / Math.floor(canvasData.naturalWidth); + + if (ratio !== 1) { + initialX *= ratio; + initialY *= ratio; + initialWidth *= ratio; + initialHeight *= ratio; + } + + const aspectRatio = initialWidth / initialHeight; + const maxSizes = getAdjustedSizes({ + aspectRatio, + width: options.maxWidth || Infinity, + height: options.maxHeight || Infinity, + }); + const minSizes = getAdjustedSizes({ + aspectRatio, + width: options.minWidth || 0, + height: options.minHeight || 0, + }, 'cover'); + let { + width, + height, + } = getAdjustedSizes({ + aspectRatio, + width: options.width || (ratio !== 1 ? source.width : initialWidth), + height: options.height || (ratio !== 1 ? source.height : initialHeight), + }); + + width = Math.min(maxSizes.width, Math.max(minSizes.width, width)); + height = Math.min(maxSizes.height, Math.max(minSizes.height, height)); + + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + + context.fillStyle = options.fillColor || 'transparent'; + context.fillRect(0, 0, width, height); + + const { imageSmoothingEnabled = true, imageSmoothingQuality } = options; + + context.imageSmoothingEnabled = imageSmoothingEnabled; + + if (imageSmoothingQuality) { + context.imageSmoothingQuality = imageSmoothingQuality; + } + + // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D.drawImage + const sourceWidth = source.width; + const sourceHeight = source.height; + + // Source canvas parameters + let srcX = initialX; + let srcY = initialY; + let srcWidth; + let srcHeight; + + // Destination canvas parameters + let dstX; + let dstY; + let dstWidth; + let dstHeight; + + if (srcX <= -initialWidth || srcX > sourceWidth) { + srcX = 0; + srcWidth = 0; + dstX = 0; + dstWidth = 0; + } else if (srcX <= 0) { + dstX = -srcX; + srcX = 0; + srcWidth = Math.min(sourceWidth, initialWidth + srcX); + dstWidth = srcWidth; + } else if (srcX <= sourceWidth) { + dstX = 0; + srcWidth = Math.min(initialWidth, sourceWidth - srcX); + dstWidth = srcWidth; + } + + if (srcWidth <= 0 || srcY <= -initialHeight || srcY > sourceHeight) { + srcY = 0; + srcHeight = 0; + dstY = 0; + dstHeight = 0; + } else if (srcY <= 0) { + dstY = -srcY; + srcY = 0; + srcHeight = Math.min(sourceHeight, initialHeight + srcY); + dstHeight = srcHeight; + } else if (srcY <= sourceHeight) { + dstY = 0; + srcHeight = Math.min(initialHeight, sourceHeight - srcY); + dstHeight = srcHeight; + } + + // All the numerical parameters should be integer for `drawImage` + // https://github.com/fengyuanchen/cropper/issues/476 + const params = [ + srcX, + srcY, + srcWidth, + srcHeight, + ]; + + // Avoid "IndexSizeError" + if (dstWidth > 0 && dstHeight > 0) { + const scale = width / initialWidth; + + params.push( + dstX * scale, + dstY * scale, + dstWidth * scale, + dstHeight * scale, + ); + } + + context.drawImage(source, ...params.map(param => Math.floor(normalizeDecimalNumber(param)))); + + return canvas; + }, + + /** + * Change the aspect ratio of the crop box. + * @param {number} aspectRatio - The new aspect ratio. + * @returns {Object} this + */ + setAspectRatio(aspectRatio) { + const { options } = this; + + if (!this.disabled && !isUndefined(aspectRatio)) { + // 0 -> NaN + options.aspectRatio = Math.max(0, aspectRatio) || NaN; + + if (this.ready) { + this.initCropBox(); + + if (this.cropped) { + this.renderCropBox(); + } + } + } + + return this; + }, + + /** + * Change the drag mode. + * @param {string} mode - The new drag mode. + * @returns {Object} this + */ + setDragMode(mode) { + const { options, dragBox, face } = this; + + if (this.loaded && !this.disabled) { + const croppable = mode === DRAG_MODE_CROP; + const movable = options.movable && mode === DRAG_MODE_MOVE; + + mode = (croppable || movable) ? mode : DRAG_MODE_NONE; + + setData(dragBox, DATA_ACTION, mode); + toggleClass(dragBox, CLASS_CROP, croppable); + toggleClass(dragBox, CLASS_MOVE, movable); + + if (!options.cropBoxMovable) { + // Sync drag mode to crop box when it is not movable + setData(face, DATA_ACTION, mode); + toggleClass(face, CLASS_CROP, croppable); + toggleClass(face, CLASS_MOVE, movable); + } + } + + return this; + }, +}; diff --git a/library/cropperjs/src/js/preview.js b/library/cropperjs/src/js/preview.js new file mode 100644 index 000000000..c47d03f4b --- /dev/null +++ b/library/cropperjs/src/js/preview.js @@ -0,0 +1,142 @@ +import { + DATA_PREVIEW, +} from './constants'; +import { + each, + empty, + extend, + getData, + getTransforms, + removeData, + setData, + setStyle, +} from './utilities'; + +export default { + initPreview() { + const { crossOrigin } = this; + const { preview } = this.options; + const url = crossOrigin ? this.crossOriginUrl : this.url; + const image = document.createElement('img'); + + if (crossOrigin) { + image.crossOrigin = crossOrigin; + } + + image.src = url; + this.viewBox.appendChild(image); + this.image2 = image; + + if (!preview) { + return; + } + + const previews = preview.querySelector ? [preview] : document.querySelectorAll(preview); + + this.previews = previews; + + each(previews, (element) => { + const img = document.createElement('img'); + + // Save the original size for recover + setData(element, DATA_PREVIEW, { + width: element.offsetWidth, + height: element.offsetHeight, + html: element.innerHTML, + }); + + if (crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + + /** + * Override img element styles + * Add `display:block` to avoid margin top issue + * Add `height:auto` to override `height` attribute on IE8 + * (Occur only when margin-top <= -height) + */ + img.style.cssText = ( + 'display:block;' + + 'width:100%;' + + 'height:auto;' + + 'min-width:0!important;' + + 'min-height:0!important;' + + 'max-width:none!important;' + + 'max-height:none!important;' + + 'image-orientation:0deg!important;"' + ); + + empty(element); + element.appendChild(img); + }); + }, + + resetPreview() { + each(this.previews, (element) => { + const data = getData(element, DATA_PREVIEW); + + setStyle(element, { + width: data.width, + height: data.height, + }); + + element.innerHTML = data.html; + removeData(element, DATA_PREVIEW); + }); + }, + + preview() { + const { imageData, canvasData, cropBoxData } = this; + const { width: cropBoxWidth, height: cropBoxHeight } = cropBoxData; + const { width, height } = imageData; + const left = cropBoxData.left - canvasData.left - imageData.left; + const top = cropBoxData.top - canvasData.top - imageData.top; + + if (!this.cropped || this.disabled) { + return; + } + + setStyle(this.image2, extend({ + width, + height, + }, getTransforms(extend({ + translateX: -left, + translateY: -top, + }, imageData)))); + + each(this.previews, (element) => { + const data = getData(element, DATA_PREVIEW); + const originalWidth = data.width; + const originalHeight = data.height; + let newWidth = originalWidth; + let newHeight = originalHeight; + let ratio = 1; + + if (cropBoxWidth) { + ratio = originalWidth / cropBoxWidth; + newHeight = cropBoxHeight * ratio; + } + + if (cropBoxHeight && newHeight > originalHeight) { + ratio = originalHeight / cropBoxHeight; + newWidth = cropBoxWidth * ratio; + newHeight = originalHeight; + } + + setStyle(element, { + width: newWidth, + height: newHeight, + }); + + setStyle(element.getElementsByTagName('img')[0], extend({ + width: width * ratio, + height: height * ratio, + }, getTransforms(extend({ + translateX: -left * ratio, + translateY: -top * ratio, + }, imageData)))); + }); + }, +}; diff --git a/library/cropperjs/src/js/render.js b/library/cropperjs/src/js/render.js new file mode 100644 index 000000000..09085ce41 --- /dev/null +++ b/library/cropperjs/src/js/render.js @@ -0,0 +1,495 @@ +import { + ACTION_ALL, + ACTION_MOVE, + CLASS_HIDDEN, + DATA_ACTION, + EVENT_CROP, +} from './constants'; +import { + addClass, + dispatchEvent, + extend, + getAdjustedSizes, + getRotatedSizes, + getTransforms, + removeClass, + setData, + setStyle, +} from './utilities'; + +export default { + render() { + this.initContainer(); + this.initCanvas(); + this.initCropBox(); + this.renderCanvas(); + + if (this.cropped) { + this.renderCropBox(); + } + }, + + initContainer() { + const { + element, + options, + container, + cropper, + } = this; + + addClass(cropper, CLASS_HIDDEN); + removeClass(element, CLASS_HIDDEN); + + const containerData = { + width: Math.max( + container.offsetWidth, + Number(options.minContainerWidth) || 200, + ), + height: Math.max( + container.offsetHeight, + Number(options.minContainerHeight) || 100, + ), + }; + + this.containerData = containerData; + + setStyle(cropper, { + width: containerData.width, + height: containerData.height, + }); + + addClass(element, CLASS_HIDDEN); + removeClass(cropper, CLASS_HIDDEN); + }, + + // Canvas (image wrapper) + initCanvas() { + const { containerData, imageData } = this; + const { viewMode } = this.options; + const rotated = Math.abs(imageData.rotate) % 180 === 90; + const naturalWidth = rotated ? imageData.naturalHeight : imageData.naturalWidth; + const naturalHeight = rotated ? imageData.naturalWidth : imageData.naturalHeight; + const aspectRatio = naturalWidth / naturalHeight; + let canvasWidth = containerData.width; + let canvasHeight = containerData.height; + + if (containerData.height * aspectRatio > containerData.width) { + if (viewMode === 3) { + canvasWidth = containerData.height * aspectRatio; + } else { + canvasHeight = containerData.width / aspectRatio; + } + } else if (viewMode === 3) { + canvasHeight = containerData.width / aspectRatio; + } else { + canvasWidth = containerData.height * aspectRatio; + } + + const canvasData = { + aspectRatio, + naturalWidth, + naturalHeight, + width: canvasWidth, + height: canvasHeight, + }; + + canvasData.left = (containerData.width - canvasWidth) / 2; + canvasData.top = (containerData.height - canvasHeight) / 2; + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + this.canvasData = canvasData; + this.limited = (viewMode === 1 || viewMode === 2); + this.limitCanvas(true, true); + this.initialImageData = extend({}, imageData); + this.initialCanvasData = extend({}, canvasData); + }, + + limitCanvas(sizeLimited, positionLimited) { + const { + options, + containerData, + canvasData, + cropBoxData, + } = this; + const { viewMode } = options; + const { aspectRatio } = canvasData; + const cropped = this.cropped && cropBoxData; + + if (sizeLimited) { + let minCanvasWidth = Number(options.minCanvasWidth) || 0; + let minCanvasHeight = Number(options.minCanvasHeight) || 0; + + if (viewMode > 1) { + minCanvasWidth = Math.max(minCanvasWidth, containerData.width); + minCanvasHeight = Math.max(minCanvasHeight, containerData.height); + + if (viewMode === 3) { + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } else if (viewMode > 0) { + if (minCanvasWidth) { + minCanvasWidth = Math.max( + minCanvasWidth, + cropped ? cropBoxData.width : 0, + ); + } else if (minCanvasHeight) { + minCanvasHeight = Math.max( + minCanvasHeight, + cropped ? cropBoxData.height : 0, + ); + } else if (cropped) { + minCanvasWidth = cropBoxData.width; + minCanvasHeight = cropBoxData.height; + + if (minCanvasHeight * aspectRatio > minCanvasWidth) { + minCanvasWidth = minCanvasHeight * aspectRatio; + } else { + minCanvasHeight = minCanvasWidth / aspectRatio; + } + } + } + + ({ width: minCanvasWidth, height: minCanvasHeight } = getAdjustedSizes({ + aspectRatio, + width: minCanvasWidth, + height: minCanvasHeight, + }, 'cover')); + + canvasData.minWidth = minCanvasWidth; + canvasData.minHeight = minCanvasHeight; + canvasData.maxWidth = Infinity; + canvasData.maxHeight = Infinity; + } + + if (positionLimited) { + if (viewMode) { + const newCanvasLeft = containerData.width - canvasData.width; + const newCanvasTop = containerData.height - canvasData.height; + + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + canvasData.maxTop = Math.max(0, newCanvasTop); + + if (cropped && this.limited) { + canvasData.minLeft = Math.min( + cropBoxData.left, + cropBoxData.left + (cropBoxData.width - canvasData.width), + ); + canvasData.minTop = Math.min( + cropBoxData.top, + cropBoxData.top + (cropBoxData.height - canvasData.height), + ); + canvasData.maxLeft = cropBoxData.left; + canvasData.maxTop = cropBoxData.top; + + if (viewMode === 2) { + if (canvasData.width >= containerData.width) { + canvasData.minLeft = Math.min(0, newCanvasLeft); + canvasData.maxLeft = Math.max(0, newCanvasLeft); + } + + if (canvasData.height >= containerData.height) { + canvasData.minTop = Math.min(0, newCanvasTop); + canvasData.maxTop = Math.max(0, newCanvasTop); + } + } + } + } else { + canvasData.minLeft = -canvasData.width; + canvasData.minTop = -canvasData.height; + canvasData.maxLeft = containerData.width; + canvasData.maxTop = containerData.height; + } + } + }, + + renderCanvas(changed, transformed) { + const { canvasData, imageData } = this; + + if (transformed) { + const { width: naturalWidth, height: naturalHeight } = getRotatedSizes({ + width: imageData.naturalWidth * Math.abs(imageData.scaleX || 1), + height: imageData.naturalHeight * Math.abs(imageData.scaleY || 1), + degree: imageData.rotate || 0, + }); + const width = canvasData.width * (naturalWidth / canvasData.naturalWidth); + const height = canvasData.height * (naturalHeight / canvasData.naturalHeight); + + canvasData.left -= (width - canvasData.width) / 2; + canvasData.top -= (height - canvasData.height) / 2; + canvasData.width = width; + canvasData.height = height; + canvasData.aspectRatio = naturalWidth / naturalHeight; + canvasData.naturalWidth = naturalWidth; + canvasData.naturalHeight = naturalHeight; + this.limitCanvas(true, false); + } + + if (canvasData.width > canvasData.maxWidth || + canvasData.width < canvasData.minWidth) { + canvasData.left = canvasData.oldLeft; + } + + if (canvasData.height > canvasData.maxHeight || + canvasData.height < canvasData.minHeight) { + canvasData.top = canvasData.oldTop; + } + + canvasData.width = Math.min( + Math.max(canvasData.width, canvasData.minWidth), + canvasData.maxWidth, + ); + canvasData.height = Math.min( + Math.max(canvasData.height, canvasData.minHeight), + canvasData.maxHeight, + ); + + this.limitCanvas(false, true); + + canvasData.left = Math.min( + Math.max(canvasData.left, canvasData.minLeft), + canvasData.maxLeft, + ); + canvasData.top = Math.min( + Math.max(canvasData.top, canvasData.minTop), + canvasData.maxTop, + ); + canvasData.oldLeft = canvasData.left; + canvasData.oldTop = canvasData.top; + + setStyle(this.canvas, extend({ + width: canvasData.width, + height: canvasData.height, + }, getTransforms({ + translateX: canvasData.left, + translateY: canvasData.top, + }))); + + this.renderImage(changed); + + if (this.cropped && this.limited) { + this.limitCropBox(true, true); + } + }, + + renderImage(changed) { + const { canvasData, imageData } = this; + const width = imageData.naturalWidth * (canvasData.width / canvasData.naturalWidth); + const height = imageData.naturalHeight * (canvasData.height / canvasData.naturalHeight); + + extend(imageData, { + width, + height, + left: (canvasData.width - width) / 2, + top: (canvasData.height - height) / 2, + }); + setStyle(this.image, extend({ + width: imageData.width, + height: imageData.height, + }, getTransforms(extend({ + translateX: imageData.left, + translateY: imageData.top, + }, imageData)))); + + if (changed) { + this.output(); + } + }, + + initCropBox() { + const { options, canvasData } = this; + const { aspectRatio } = options; + const autoCropArea = Number(options.autoCropArea) || 0.8; + const cropBoxData = { + width: canvasData.width, + height: canvasData.height, + }; + + if (aspectRatio) { + if (canvasData.height * aspectRatio > canvasData.width) { + cropBoxData.height = cropBoxData.width / aspectRatio; + } else { + cropBoxData.width = cropBoxData.height * aspectRatio; + } + } + + this.cropBoxData = cropBoxData; + this.limitCropBox(true, true); + + // Initialize auto crop area + cropBoxData.width = Math.min( + Math.max(cropBoxData.width, cropBoxData.minWidth), + cropBoxData.maxWidth, + ); + cropBoxData.height = Math.min( + Math.max(cropBoxData.height, cropBoxData.minHeight), + cropBoxData.maxHeight, + ); + + // The width/height of auto crop area must large than "minWidth/Height" + cropBoxData.width = Math.max( + cropBoxData.minWidth, + cropBoxData.width * autoCropArea, + ); + cropBoxData.height = Math.max( + cropBoxData.minHeight, + cropBoxData.height * autoCropArea, + ); + cropBoxData.left = ( + canvasData.left + ((canvasData.width - cropBoxData.width) / 2) + ); + cropBoxData.top = ( + canvasData.top + ((canvasData.height - cropBoxData.height) / 2) + ); + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + this.initialCropBoxData = extend({}, cropBoxData); + }, + + limitCropBox(sizeLimited, positionLimited) { + const { + options, + containerData, + canvasData, + cropBoxData, + limited, + } = this; + const { aspectRatio } = options; + + if (sizeLimited) { + let minCropBoxWidth = Number(options.minCropBoxWidth) || 0; + let minCropBoxHeight = Number(options.minCropBoxHeight) || 0; + let maxCropBoxWidth = Math.min( + containerData.width, + limited ? canvasData.width : containerData.width, + ); + let maxCropBoxHeight = Math.min( + containerData.height, + limited ? canvasData.height : containerData.height, + ); + + // The min/maxCropBoxWidth/Height must be less than container's width/height + minCropBoxWidth = Math.min(minCropBoxWidth, containerData.width); + minCropBoxHeight = Math.min(minCropBoxHeight, containerData.height); + + if (aspectRatio) { + if (minCropBoxWidth && minCropBoxHeight) { + if (minCropBoxHeight * aspectRatio > minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + } else if (minCropBoxWidth) { + minCropBoxHeight = minCropBoxWidth / aspectRatio; + } else if (minCropBoxHeight) { + minCropBoxWidth = minCropBoxHeight * aspectRatio; + } + + if (maxCropBoxHeight * aspectRatio > maxCropBoxWidth) { + maxCropBoxHeight = maxCropBoxWidth / aspectRatio; + } else { + maxCropBoxWidth = maxCropBoxHeight * aspectRatio; + } + } + + // The minWidth/Height must be less than maxWidth/Height + cropBoxData.minWidth = Math.min(minCropBoxWidth, maxCropBoxWidth); + cropBoxData.minHeight = Math.min(minCropBoxHeight, maxCropBoxHeight); + cropBoxData.maxWidth = maxCropBoxWidth; + cropBoxData.maxHeight = maxCropBoxHeight; + } + + if (positionLimited) { + if (limited) { + cropBoxData.minLeft = Math.max(0, canvasData.left); + cropBoxData.minTop = Math.max(0, canvasData.top); + cropBoxData.maxLeft = Math.min( + containerData.width, + canvasData.left + canvasData.width, + ) - cropBoxData.width; + cropBoxData.maxTop = Math.min( + containerData.height, + canvasData.top + canvasData.height, + ) - cropBoxData.height; + } else { + cropBoxData.minLeft = 0; + cropBoxData.minTop = 0; + cropBoxData.maxLeft = containerData.width - cropBoxData.width; + cropBoxData.maxTop = containerData.height - cropBoxData.height; + } + } + }, + + renderCropBox() { + const { options, containerData, cropBoxData } = this; + + if (cropBoxData.width > cropBoxData.maxWidth || + cropBoxData.width < cropBoxData.minWidth) { + cropBoxData.left = cropBoxData.oldLeft; + } + + if (cropBoxData.height > cropBoxData.maxHeight || + cropBoxData.height < cropBoxData.minHeight) { + cropBoxData.top = cropBoxData.oldTop; + } + + cropBoxData.width = Math.min( + Math.max(cropBoxData.width, cropBoxData.minWidth), + cropBoxData.maxWidth, + ); + cropBoxData.height = Math.min( + Math.max(cropBoxData.height, cropBoxData.minHeight), + cropBoxData.maxHeight, + ); + + this.limitCropBox(false, true); + + cropBoxData.left = Math.min( + Math.max(cropBoxData.left, cropBoxData.minLeft), + cropBoxData.maxLeft, + ); + cropBoxData.top = Math.min( + Math.max(cropBoxData.top, cropBoxData.minTop), + cropBoxData.maxTop, + ); + cropBoxData.oldLeft = cropBoxData.left; + cropBoxData.oldTop = cropBoxData.top; + + if (options.movable && options.cropBoxMovable) { + // Turn to move the canvas when the crop box is equal to the container + setData(this.face, DATA_ACTION, cropBoxData.width >= containerData.width && + cropBoxData.height >= containerData.height ? ACTION_MOVE : ACTION_ALL); + } + + setStyle(this.cropBox, extend({ + width: cropBoxData.width, + height: cropBoxData.height, + }, getTransforms({ + translateX: cropBoxData.left, + translateY: cropBoxData.top, + }))); + + if (this.cropped && this.limited) { + this.limitCanvas(true, true); + } + + if (!this.disabled) { + this.output(); + } + }, + + output() { + this.preview(); + + if (this.complete) { + dispatchEvent(this.element, EVENT_CROP, this.getData()); + } + }, +}; diff --git a/library/cropperjs/src/js/template.js b/library/cropperjs/src/js/template.js new file mode 100644 index 000000000..589b46a78 --- /dev/null +++ b/library/cropperjs/src/js/template.js @@ -0,0 +1,27 @@ +export default ( + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '
    ' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '
    ' + + '
    ' +); diff --git a/library/cropperjs/src/js/utilities.js b/library/cropperjs/src/js/utilities.js new file mode 100644 index 000000000..50b586a76 --- /dev/null +++ b/library/cropperjs/src/js/utilities.js @@ -0,0 +1,985 @@ +import { + WINDOW, +} from './constants'; + +/** + * Check if the given value is not a number. + */ +export const isNaN = Number.isNaN || WINDOW.isNaN; + +/** + * Check if the given value is a number. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a number, else `false`. + */ +export function isNumber(value) { + return typeof value === 'number' && !isNaN(value); +} + +/** + * Check if the given value is undefined. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is undefined, else `false`. + */ +export function isUndefined(value) { + return typeof value === 'undefined'; +} + +/** + * Check if the given value is an object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is an object, else `false`. + */ +export function isObject(value) { + return typeof value === 'object' && value !== null; +} + +const { hasOwnProperty } = Object.prototype; + +/** + * Check if the given value is a plain object. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a plain object, else `false`. + */ +export function isPlainObject(value) { + if (!isObject(value)) { + return false; + } + + try { + const { constructor } = value; + const { prototype } = constructor; + + return constructor && prototype && hasOwnProperty.call(prototype, 'isPrototypeOf'); + } catch (e) { + return false; + } +} + +/** + * Check if the given value is a function. + * @param {*} value - The value to check. + * @returns {boolean} Returns `true` if the given value is a function, else `false`. + */ +export function isFunction(value) { + return typeof value === 'function'; +} + +/** + * Iterate the given data. + * @param {*} data - The data to iterate. + * @param {Function} callback - The process function for each element. + * @returns {*} The original data. + */ +export function each(data, callback) { + if (data && isFunction(callback)) { + if (Array.isArray(data) || isNumber(data.length)/* array-like */) { + const { length } = data; + let i; + + for (i = 0; i < length; i += 1) { + if (callback.call(data, data[i], i, data) === false) { + break; + } + } + } else if (isObject(data)) { + Object.keys(data).forEach((key) => { + callback.call(data, data[key], key, data); + }); + } + } + + return data; +} + +/** + * Extend the given object. + * @param {*} obj - The object to be extended. + * @param {*} args - The rest objects which will be merged to the first object. + * @returns {Object} The extended object. + */ +export function extend(obj, ...args) { + if (isObject(obj) && args.length > 0) { + if (Object.assign) { + return Object.assign(obj, ...args); + } + + args.forEach((arg) => { + if (isObject(arg)) { + Object.keys(arg).forEach((key) => { + obj[key] = arg[key]; + }); + } + }); + } + + return obj; +} + +/** + * Takes a function and returns a new one that will always have a particular context. + * @param {Function} fn - The target function. + * @param {Object} context - The new context for the function. + * @returns {boolean} The new function. + */ +export function proxy(fn, context, ...args) { + return (...args2) => fn.apply(context, args.concat(args2)); +} + +const REGEXP_DECIMALS = /\.\d*(?:0|9){12}\d*$/i; + +/** + * Normalize decimal number. + * Check out {@link http://0.30000000000000004.com/ } + * @param {number} value - The value to normalize. + * @param {number} [times=100000000000] - The times for normalizing. + * @returns {number} Returns the normalized number. + */ +export function normalizeDecimalNumber(value, times = 100000000000) { + return REGEXP_DECIMALS.test(value) ? (Math.round(value * times) / times) : value; +} + +const REGEXP_SUFFIX = /^(?:width|height|left|top|marginLeft|marginTop)$/; + +/** + * Apply styles to the given element. + * @param {Element} element - The target element. + * @param {Object} styles - The styles for applying. + */ +export function setStyle(element, styles) { + const { style } = element; + + each(styles, (value, property) => { + if (REGEXP_SUFFIX.test(property) && isNumber(value)) { + value += 'px'; + } + + style[property] = value; + }); +} + +/** + * Check if the given element has a special class. + * @param {Element} element - The element to check. + * @param {string} value - The class to search. + * @returns {boolean} Returns `true` if the special class was found. + */ +export function hasClass(element, value) { + return element.classList ? + element.classList.contains(value) : + element.className.indexOf(value) > -1; +} + +/** + * Add classes to the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be added. + */ +export function addClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, (elem) => { + addClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.add(value); + return; + } + + const className = element.className.trim(); + + if (!className) { + element.className = value; + } else if (className.indexOf(value) < 0) { + element.className = `${className} ${value}`; + } +} + +/** + * Remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be removed. + */ +export function removeClass(element, value) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, (elem) => { + removeClass(elem, value); + }); + return; + } + + if (element.classList) { + element.classList.remove(value); + return; + } + + if (element.className.indexOf(value) >= 0) { + element.className = element.className.replace(value, ''); + } +} + +/** + * Add or remove classes from the given element. + * @param {Element} element - The target element. + * @param {string} value - The classes to be toggled. + * @param {boolean} added - Add only. + */ +export function toggleClass(element, value, added) { + if (!value) { + return; + } + + if (isNumber(element.length)) { + each(element, (elem) => { + toggleClass(elem, value, added); + }); + return; + } + + // IE10-11 doesn't support the second parameter of `classList.toggle` + if (added) { + addClass(element, value); + } else { + removeClass(element, value); + } +} + +const REGEXP_HYPHENATE = /([a-z\d])([A-Z])/g; + +/** + * Hyphenate the given value. + * @param {string} value - The value to hyphenate. + * @returns {string} The hyphenated value. + */ +export function hyphenate(value) { + return value.replace(REGEXP_HYPHENATE, '$1-$2').toLowerCase(); +} + +/** + * Get data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to get. + * @returns {string} The data value. + */ +export function getData(element, name) { + if (isObject(element[name])) { + return element[name]; + } else if (element.dataset) { + return element.dataset[name]; + } + + return element.getAttribute(`data-${hyphenate(name)}`); +} + +/** + * Set data to the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to set. + * @param {string} data - The data value. + */ +export function setData(element, name, data) { + if (isObject(data)) { + element[name] = data; + } else if (element.dataset) { + element.dataset[name] = data; + } else { + element.setAttribute(`data-${hyphenate(name)}`, data); + } +} + +/** + * Remove data from the given element. + * @param {Element} element - The target element. + * @param {string} name - The data key to remove. + */ +export function removeData(element, name) { + if (isObject(element[name])) { + try { + delete element[name]; + } catch (e) { + element[name] = null; + } + } else if (element.dataset) { + // #128 Safari not allows to delete dataset property + try { + delete element.dataset[name]; + } catch (e) { + element.dataset[name] = null; + } + } else { + element.removeAttribute(`data-${hyphenate(name)}`); + } +} + +const REGEXP_SPACES = /\s\s*/; + +/** + * Remove event listener from the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +export function removeListener(element, type, listener, options = {}) { + if (!isFunction(listener)) { + return; + } + + const types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, (t) => { + removeListener(element, t, listener, options); + }); + return; + } + + if (element.removeEventListener) { + element.removeEventListener(type, listener, options); + } else if (element.detachEvent) { + element.detachEvent(`on${type}`, listener); + } +} + +/** + * Add event listener to the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Function} listener - The event listener. + * @param {Object} options - The event options. + */ +export function addListener(element, type, listener, options = {}) { + if (!isFunction(listener)) { + return; + } + + const types = type.trim().split(REGEXP_SPACES); + + if (types.length > 1) { + each(types, (t) => { + addListener(element, t, listener, options); + }); + return; + } + + if (options.once) { + const originalListener = listener; + + listener = (...args) => { + removeListener(element, type, listener, options); + return originalListener.apply(element, args); + }; + } + + if (element.addEventListener) { + element.addEventListener(type, listener, options); + } else if (element.attachEvent) { + element.attachEvent(`on${type}`, listener); + } +} + +/** + * Dispatch event on the target element. + * @param {Element} element - The event target. + * @param {string} type - The event type(s). + * @param {Object} data - The additional event data. + * @returns {boolean} Indicate if the event is default prevented or not. + */ +export function dispatchEvent(element, type, data) { + if (element.dispatchEvent) { + let event; + + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (isFunction(Event) && isFunction(CustomEvent)) { + if (isUndefined(data)) { + event = new Event(type, { + bubbles: true, + cancelable: true, + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true, + }); + } + } else if (isUndefined(data)) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent(`on${type}`); + } + + return true; +} + +/** + * Get the offset base on the document. + * @param {Element} element - The target element. + * @returns {Object} The offset data. + */ +export function getOffset(element) { + const doc = document.documentElement; + const box = element.getBoundingClientRect(); + + return { + left: box.left + ( + (window.scrollX || (doc && doc.scrollLeft) || 0) - ((doc && doc.clientLeft) || 0) + ), + top: box.top + ( + (window.scrollY || (doc && doc.scrollTop) || 0) - ((doc && doc.clientTop) || 0) + ), + }; +} + +/** + * Empty an element. + * @param {Element} element - The element to empty. + */ +export function empty(element) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } +} + +const { location } = WINDOW; +const REGEXP_ORIGINS = /^(https?:)\/\/([^:/?#]+):?(\d*)/i; + +/** + * Check if the given URL is a cross origin URL. + * @param {string} url - The target URL. + * @returns {boolean} Returns `true` if the given URL is a cross origin URL, else `false`. + */ +export function isCrossOriginURL(url) { + const parts = url.match(REGEXP_ORIGINS); + + return parts && ( + parts[1] !== location.protocol || + parts[2] !== location.hostname || + parts[3] !== location.port + ); +} + +/** + * Add timestamp to the given URL. + * @param {string} url - The target URL. + * @returns {string} The result URL. + */ +export function addTimestamp(url) { + const timestamp = `timestamp=${(new Date()).getTime()}`; + + return (url + (url.indexOf('?') === -1 ? '?' : '&') + timestamp); +} + +/** + * Get transforms base on the given object. + * @param {Object} obj - The target object. + * @returns {string} A string contains transform values. + */ +export function getTransforms({ + rotate, + scaleX, + scaleY, + translateX, + translateY, +}) { + const values = []; + + if (isNumber(translateX) && translateX !== 0) { + values.push(`translateX(${translateX}px)`); + } + + if (isNumber(translateY) && translateY !== 0) { + values.push(`translateY(${translateY}px)`); + } + + // Rotate should come first before scale to match orientation transform + if (isNumber(rotate) && rotate !== 0) { + values.push(`rotate(${rotate}deg)`); + } + + if (isNumber(scaleX) && scaleX !== 1) { + values.push(`scaleX(${scaleX})`); + } + + if (isNumber(scaleY) && scaleY !== 1) { + values.push(`scaleY(${scaleY})`); + } + + const transform = values.length ? values.join(' ') : 'none'; + + return { + WebkitTransform: transform, + msTransform: transform, + transform, + }; +} + +const { navigator } = WINDOW; +const IS_SAFARI_OR_UIWEBVIEW = navigator && /(Macintosh|iPhone|iPod|iPad).*AppleWebKit/i.test(navigator.userAgent); + +/** + * Get an image's natural sizes. + * @param {string} image - The target image. + * @param {Function} callback - The callback function. + */ +export function getImageNaturalSizes(image, callback) { + // Modern browsers (except Safari) + if (image.naturalWidth && !IS_SAFARI_OR_UIWEBVIEW) { + callback(image.naturalWidth, image.naturalHeight); + return; + } + + const newImage = document.createElement('img'); + const body = document.body || document.documentElement; + + newImage.onload = () => { + callback(newImage.width, newImage.height); + + if (!IS_SAFARI_OR_UIWEBVIEW) { + body.removeChild(newImage); + } + }; + + newImage.src = image.src; + + // iOS Safari will convert the image automatically + // with its orientation once append it into DOM (#279) + if (!IS_SAFARI_OR_UIWEBVIEW) { + newImage.style.cssText = ( + 'left:0;' + + 'max-height:none!important;' + + 'max-width:none!important;' + + 'min-height:0!important;' + + 'min-width:0!important;' + + 'opacity:0;' + + 'position:absolute;' + + 'top:0;' + + 'z-index:-1;' + ); + body.appendChild(newImage); + } +} + +/** + * Get the max ratio of a group of pointers. + * @param {string} pointers - The target pointers. + * @returns {number} The result ratio. + */ +export function getMaxZoomRatio(pointers) { + const pointers2 = extend({}, pointers); + const ratios = []; + + each(pointers, (pointer, pointerId) => { + delete pointers2[pointerId]; + + each(pointers2, (pointer2) => { + const x1 = Math.abs(pointer.startX - pointer2.startX); + const y1 = Math.abs(pointer.startY - pointer2.startY); + const x2 = Math.abs(pointer.endX - pointer2.endX); + const y2 = Math.abs(pointer.endY - pointer2.endY); + const z1 = Math.sqrt((x1 * x1) + (y1 * y1)); + const z2 = Math.sqrt((x2 * x2) + (y2 * y2)); + const ratio = (z2 - z1) / z1; + + ratios.push(ratio); + }); + }); + + ratios.sort((a, b) => Math.abs(a) < Math.abs(b)); + + return ratios[0]; +} + +/** + * Get a pointer from an event object. + * @param {Object} event - The target event object. + * @param {boolean} endOnly - Indicates if only returns the end point coordinate or not. + * @returns {Object} The result pointer contains start and/or end point coordinates. + */ +export function getPointer({ pageX, pageY }, endOnly) { + const end = { + endX: pageX, + endY: pageY, + }; + + if (endOnly) { + return end; + } + + return extend({ + startX: pageX, + startY: pageY, + }, end); +} + +/** + * Get the center point coordinate of a group of pointers. + * @param {Object} pointers - The target pointers. + * @returns {Object} The center point coordinate. + */ +export function getPointersCenter(pointers) { + let pageX = 0; + let pageY = 0; + let count = 0; + + each(pointers, ({ startX, startY }) => { + pageX += startX; + pageY += startY; + count += 1; + }); + + pageX /= count; + pageY /= count; + + return { + pageX, + pageY, + }; +} + +/** + * Check if the given value is a finite number. + */ +export const isFinite = Number.isFinite || WINDOW.isFinite; + +/** + * Get the max sizes in a rectangle under the given aspect ratio. + * @param {Object} data - The original sizes. + * @param {string} [type='contain'] - The adjust type. + * @returns {Object} The result sizes. + */ +export function getAdjustedSizes( + { + aspectRatio, + height, + width, + }, + type = 'contain', // or 'cover' +) { + const isValidNumber = value => isFinite(value) && value > 0; + + if (isValidNumber(width) && isValidNumber(height)) { + const adjustedWidth = height * aspectRatio; + + if ((type === 'contain' && adjustedWidth > width) || (type === 'cover' && adjustedWidth < width)) { + height = width / aspectRatio; + } else { + width = height * aspectRatio; + } + } else if (isValidNumber(width)) { + height = width / aspectRatio; + } else if (isValidNumber(height)) { + width = height * aspectRatio; + } + + return { + width, + height, + }; +} + +/** + * Get the new sizes of a rectangle after rotated. + * @param {Object} data - The original sizes. + * @returns {Object} The result sizes. + */ +export function getRotatedSizes({ width, height, degree }) { + degree = Math.abs(degree) % 180; + + if (degree === 90) { + return { + width: height, + height: width, + }; + } + + const arc = ((degree % 90) * Math.PI) / 180; + const sinArc = Math.sin(arc); + const cosArc = Math.cos(arc); + const newWidth = (width * cosArc) + (height * sinArc); + const newHeight = (width * sinArc) + (height * cosArc); + + return degree > 90 ? { + width: newHeight, + height: newWidth, + } : { + width: newWidth, + height: newHeight, + }; +} + +/** + * Get a canvas which drew the given image. + * @param {HTMLImageElement} image - The image for drawing. + * @param {Object} imageData - The image data. + * @param {Object} canvasData - The canvas data. + * @param {Object} options - The options. + * @returns {HTMLCanvasElement} The result canvas. + */ +export function getSourceCanvas( + image, + { + rotate = 0, + scaleX = 1, + scaleY = 1, + }, + { + aspectRatio, + naturalWidth, + naturalHeight, + }, + { + fillColor = 'transparent', + imageSmoothingEnabled = true, + imageSmoothingQuality = 'low', + maxWidth = Infinity, + maxHeight = Infinity, + minWidth = 0, + minHeight = 0, + }, +) { + const canvas = document.createElement('canvas'); + const context = canvas.getContext('2d'); + const maxSizes = getAdjustedSizes({ + aspectRatio, + width: maxWidth, + height: maxHeight, + }); + const minSizes = getAdjustedSizes({ + aspectRatio, + width: minWidth, + height: minHeight, + }, 'cover'); + const width = Math.min(maxSizes.width, Math.max(minSizes.width, naturalWidth)); + const height = Math.min(maxSizes.height, Math.max(minSizes.height, naturalHeight)); + const params = [ + -width / 2, + -height / 2, + width, + height, + ]; + + canvas.width = normalizeDecimalNumber(width); + canvas.height = normalizeDecimalNumber(height); + context.fillStyle = fillColor; + context.fillRect(0, 0, width, height); + context.save(); + context.translate(width / 2, height / 2); + context.rotate((rotate * Math.PI) / 180); + context.scale(scaleX, scaleY); + context.imageSmoothingEnabled = imageSmoothingEnabled; + context.imageSmoothingQuality = imageSmoothingQuality; + context.drawImage(image, ...params.map(param => Math.floor(normalizeDecimalNumber(param)))); + context.restore(); + return canvas; +} + +const { fromCharCode } = String; + +/** + * Get string from char code in data view. + * @param {DataView} dataView - The data view for read. + * @param {number} start - The start index. + * @param {number} length - The read length. + * @returns {string} The read result. + */ +export function getStringFromCharCode(dataView, start, length) { + let str = ''; + let i; + + length += start; + + for (i = start; i < length; i += 1) { + str += fromCharCode(dataView.getUint8(i)); + } + + return str; +} + +const REGEXP_DATA_URL_HEAD = /^data:.*,/; + +/** + * Transform Data URL to array buffer. + * @param {string} dataURL - The Data URL to transform. + * @returns {ArrayBuffer} The result array buffer. + */ +export function dataURLToArrayBuffer(dataURL) { + const base64 = dataURL.replace(REGEXP_DATA_URL_HEAD, ''); + const binary = atob(base64); + const arrayBuffer = new ArrayBuffer(binary.length); + const uint8 = new Uint8Array(arrayBuffer); + + each(uint8, (value, i) => { + uint8[i] = binary.charCodeAt(i); + }); + + return arrayBuffer; +} + +/** + * Transform array buffer to Data URL. + * @param {ArrayBuffer} arrayBuffer - The array buffer to transform. + * @param {string} mimeType - The mime type of the Data URL. + * @returns {string} The result Data URL. + */ +export function arrayBufferToDataURL(arrayBuffer, mimeType) { + const uint8 = new Uint8Array(arrayBuffer); + let data = ''; + + // TypedArray.prototype.forEach is not supported in some browsers. + each(uint8, (value) => { + data += fromCharCode(value); + }); + + return `data:${mimeType};base64,${btoa(data)}`; +} + +/** + * Get orientation value from given array buffer. + * @param {ArrayBuffer} arrayBuffer - The array buffer to read. + * @returns {number} The read orientation value. + */ +export function getOrientation(arrayBuffer) { + const dataView = new DataView(arrayBuffer); + let orientation; + let littleEndian; + let app1Start; + let ifdStart; + + // Only handle JPEG image (start by 0xFFD8) + if (dataView.getUint8(0) === 0xFF && dataView.getUint8(1) === 0xD8) { + const length = dataView.byteLength; + let offset = 2; + + while (offset < length) { + if (dataView.getUint8(offset) === 0xFF && dataView.getUint8(offset + 1) === 0xE1) { + app1Start = offset; + break; + } + + offset += 1; + } + } + + if (app1Start) { + const exifIDCode = app1Start + 4; + const tiffOffset = app1Start + 10; + + if (getStringFromCharCode(dataView, exifIDCode, 4) === 'Exif') { + const endianness = dataView.getUint16(tiffOffset); + + littleEndian = endianness === 0x4949; + + if (littleEndian || endianness === 0x4D4D /* bigEndian */) { + if (dataView.getUint16(tiffOffset + 2, littleEndian) === 0x002A) { + const firstIFDOffset = dataView.getUint32(tiffOffset + 4, littleEndian); + + if (firstIFDOffset >= 0x00000008) { + ifdStart = tiffOffset + firstIFDOffset; + } + } + } + } + } + + if (ifdStart) { + const length = dataView.getUint16(ifdStart, littleEndian); + let offset; + let i; + + for (i = 0; i < length; i += 1) { + offset = ifdStart + (i * 12) + 2; + + if (dataView.getUint16(offset, littleEndian) === 0x0112 /* Orientation */) { + // 8 is the offset of the current tag's value + offset += 8; + + // Get the original orientation value + orientation = dataView.getUint16(offset, littleEndian); + + // Override the orientation with its default value + dataView.setUint16(offset, 1, littleEndian); + break; + } + } + } + + return orientation; +} + +/** + * Parse Exif Orientation value. + * @param {number} orientation - The orientation to parse. + * @returns {Object} The parsed result. + */ +export function parseOrientation(orientation) { + let rotate = 0; + let scaleX = 1; + let scaleY = 1; + + switch (orientation) { + // Flip horizontal + case 2: + scaleX = -1; + break; + + // Rotate left 180° + case 3: + rotate = -180; + break; + + // Flip vertical + case 4: + scaleY = -1; + break; + + // Flip vertical and rotate right 90° + case 5: + rotate = 90; + scaleY = -1; + break; + + // Rotate right 90° + case 6: + rotate = 90; + break; + + // Flip horizontal and rotate right 90° + case 7: + rotate = 90; + scaleX = -1; + break; + + // Rotate left 90° + case 8: + rotate = -90; + break; + + default: + } + + return { + rotate, + scaleX, + scaleY, + }; +} diff --git a/library/cropperjs/test/css/main.css b/library/cropperjs/test/css/main.css new file mode 100644 index 000000000..6a86d123c --- /dev/null +++ b/library/cropperjs/test/css/main.css @@ -0,0 +1,9 @@ +.container { + max-width: 640px; + max-height: 360px; + margin: 20px auto; +} + +.container > img { + max-width: 100%; +} diff --git a/library/cropperjs/test/events/crop.js b/library/cropperjs/test/events/crop.js new file mode 100644 index 000000000..1f769cf60 --- /dev/null +++ b/library/cropperjs/test/events/crop.js @@ -0,0 +1,21 @@ +QUnit.test('events#crop', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(7); + + image.addEventListener('crop', function (e) { + assert.ok(util.isNumber(e.detail.x)); + assert.ok(util.isNumber(e.detail.y)); + assert.ok(util.isNumber(e.detail.width)); + assert.ok(util.isNumber(e.detail.height)); + assert.ok(util.isNumber(e.detail.rotate)); + assert.ok(util.isNumber(e.detail.scaleX)); + assert.ok(util.isNumber(e.detail.scaleY)); + + done(); + }); + + return new Cropper(image); +}); diff --git a/library/cropperjs/test/events/cropend.js b/library/cropperjs/test/events/cropend.js new file mode 100644 index 000000000..1f18fb435 --- /dev/null +++ b/library/cropperjs/test/events/cropend.js @@ -0,0 +1,24 @@ +QUnit.test('events#cropend', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + image.addEventListener('ready', function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointermove' : 'mousemove'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }); + + image.addEventListener('cropend', function (e) { + assert.strictEqual(e.detail.action, 'crop'); + }); + + return new Cropper(image); +}); diff --git a/library/cropperjs/test/events/cropmove.js b/library/cropperjs/test/events/cropmove.js new file mode 100644 index 000000000..c695b7fdd --- /dev/null +++ b/library/cropperjs/test/events/cropmove.js @@ -0,0 +1,24 @@ +QUnit.test('events#cropmove', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + image.addEventListener('ready', function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointermove' : 'mousemove'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }); + + image.addEventListener('cropmove', function (e) { + assert.strictEqual(e.detail.action, 'crop'); + }); + + return new Cropper(image); +}); diff --git a/library/cropperjs/test/events/cropstart.js b/library/cropperjs/test/events/cropstart.js new file mode 100644 index 000000000..7d9b597a0 --- /dev/null +++ b/library/cropperjs/test/events/cropstart.js @@ -0,0 +1,56 @@ +QUnit.test('events#cropstart', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + image.addEventListener('ready', function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }); + + image.addEventListener('cropstart', function (e) { + assert.strictEqual(e.detail.action, 'crop'); + }); + + return new Cropper(image); +}); + +QUnit.test('events#cropstart: default prevented', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(0); + + image.addEventListener('ready', function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointermove' : 'mousemove'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }); + + image.addEventListener('cropstart', function (e) { + e.preventDefault(); + }); + + image.addEventListener('cropmove', function () { + assert.ok(false); + }); + + image.addEventListener('cropend', function () { + assert.ok(false); + }); + + return new Cropper(image); +}); diff --git a/library/cropperjs/test/events/ready.js b/library/cropperjs/test/events/ready.js new file mode 100644 index 000000000..fbec2ff0c --- /dev/null +++ b/library/cropperjs/test/events/ready.js @@ -0,0 +1,15 @@ +QUnit.test('events#ready', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + image.addEventListener('ready', function () { + assert.ok(true); + + done(); + }); + + return new Cropper(image); +}); diff --git a/library/cropperjs/test/events/zoom.js b/library/cropperjs/test/events/zoom.js new file mode 100644 index 000000000..99fda34b5 --- /dev/null +++ b/library/cropperjs/test/events/zoom.js @@ -0,0 +1,46 @@ +QUnit.test('events#zoom', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(3); + + image.addEventListener('ready', function () { + var cropper = this.cropper; + + cropper.zoom(0.1); + + done(); + }); + + image.addEventListener('zoom', function (e) { + assert.ok(e.detail.ratio > 0); + assert.ok(e.detail.oldRatio > 0); + assert.ok(e.detail.ratio > e.detail.oldRatio); + }); + + return new Cropper(image); +}); + +QUnit.test('events#zoom: default prevented', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + image.addEventListener('ready', function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + + assert.deepEqual(cropper.zoom(0.1).getCanvasData(), canvasData); + + done(); + }); + + image.addEventListener('zoom', function (e) { + e.preventDefault(); + }); + + return new Cropper(image); +}); diff --git a/library/cropperjs/test/index.html b/library/cropperjs/test/index.html new file mode 100644 index 000000000..bdcaf6b21 --- /dev/null +++ b/library/cropperjs/test/index.html @@ -0,0 +1,90 @@ + + + + + + + Cropper.js + + + + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/cropperjs/test/js/main.js b/library/cropperjs/test/js/main.js new file mode 100644 index 000000000..79fda799f --- /dev/null +++ b/library/cropperjs/test/js/main.js @@ -0,0 +1,74 @@ +window.Util = { + isNumber: function (n) { + return typeof n === 'number' && !isNaN(n); + }, + isFunction: function (fn) { + return typeof fn === 'function'; + }, + hasClass: function (element, className) { + return element.classList.contains(className); + }, + getByClass: function (element, className) { + return element.getElementsByClassName ? + element.getElementsByClassName(className) : + element.querySelectorAll('.' + className); + }, + createImage: function (attrs) { + var container = document.createElement('div'); + var image = new Image(); + var attr; + + if (typeof attrs !== 'object') { + attrs = {}; + } + + if (!attrs.src) { + attrs.src = '../docs/images/picture.jpg'; + } + + for (attr in attrs) { + if (attrs.hasOwnProperty(attr)) { + image[attr] = attrs[attr]; + } + } + + container.className = 'container'; + container.appendChild(image); + document.body.appendChild(container); + + return image; + }, + dispatchEvent: function (element, type, data) { + var event; + + if (element.dispatchEvent) { + // Event and CustomEvent on IE9-11 are global objects, not constructors + if (typeof Event === 'function' && typeof CustomEvent === 'function') { + if (!data) { + event = new Event(type, { + bubbles: true, + cancelable: true + }); + } else { + event = new CustomEvent(type, { + detail: data, + bubbles: true, + cancelable: true + }); + } + } else if (!data) { + event = document.createEvent('Event'); + event.initEvent(type, true, true); + } else { + event = document.createEvent('CustomEvent'); + event.initCustomEvent(type, true, true, data); + } + + // IE9+ + return element.dispatchEvent(event); + } else if (element.fireEvent) { + // IE6-10 (native events only) + return element.fireEvent('on' + type); + } + } +}; diff --git a/library/cropperjs/test/methods/clear.js b/library/cropperjs/test/methods/clear.js new file mode 100644 index 000000000..6510ebad2 --- /dev/null +++ b/library/cropperjs/test/methods/clear.js @@ -0,0 +1,29 @@ +QUnit.test('methods#clear', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + cropper.clear(); + assert.notOk(cropper.cropped); + assert.deepEqual(cropper.getData(), { + x: 0, + y: 0, + width: 0, + height: 0, + rotate: 0, + scaleX: 1, + scaleY: 1 + }); + assert.deepEqual(cropper.getCropBoxData(), {}); + assert.ok(util.hasClass(cropper.cropBox, 'cropper-hidden')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/crop.js b/library/cropperjs/test/methods/crop.js new file mode 100644 index 000000000..e4ae679f1 --- /dev/null +++ b/library/cropperjs/test/methods/crop.js @@ -0,0 +1,24 @@ +QUnit.test('methods#crop', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + autoCrop: false, + + ready: function () { + var cropper = this.cropper; + + assert.notOk(cropper.cropped); + assert.ok(util.hasClass(cropper.cropBox, 'cropper-hidden')); + + cropper.crop(); + assert.ok(cropper.cropped); + assert.notOk(util.hasClass(cropper.cropBox, 'cropper-hidden')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/destroy.js b/library/cropperjs/test/methods/destroy.js new file mode 100644 index 000000000..cb65e0696 --- /dev/null +++ b/library/cropperjs/test/methods/destroy.js @@ -0,0 +1,22 @@ +QUnit.test('methods#destroy', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + assert.ok(typeof cropper === 'object'); + assert.ok(util.hasClass(image, 'cropper-hidden')); + + cropper.destroy(); + assert.ok(typeof this.cropper === 'undefined'); + assert.notOk(util.hasClass(image, 'cropper-hidden')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/disable.js b/library/cropperjs/test/methods/disable.js new file mode 100644 index 000000000..c87f7aa91 --- /dev/null +++ b/library/cropperjs/test/methods/disable.js @@ -0,0 +1,60 @@ +QUnit.test('methods#disable', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(11); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var options = cropper.options; + var cropBoxData; + var canvasData; + var imageData; + var action; + + cropper.disable(); + assert.ok(cropper.disabled); + assert.ok(util.hasClass(cropper.cropper, 'cropper-disabled')); + + cropBoxData = cropper.getCropBoxData(); + cropper.clear(); + assert.deepEqual(cropper.getCropBoxData(), cropBoxData); + + imageData = cropper.getImageData(); + cropper.move(10, 10); + assert.deepEqual(cropper.getImageData(), imageData); + + cropper.zoom(0.5); + assert.strictEqual(cropper.getImageData().ratio, imageData.ratio); + + cropper.rotate(15); + assert.strictEqual(cropper.getImageData().rotate, imageData.rotate); + + cropper.scale(-1); + assert.strictEqual(cropper.getImageData().scaleX, imageData.scaleX); + + canvasData = cropper.getCanvasData(); + cropper.setCanvasData({ + width: canvasData.width - 160 + }); + assert.deepEqual(cropper.getCanvasData(), canvasData); + + cropBoxData = cropper.getCropBoxData(); + cropper.setCropBoxData({ + height: cropBoxData.height - 90 + }); + assert.deepEqual(cropper.getCropBoxData(), cropBoxData); + + cropper.setAspectRatio(0.618); + assert.ok(isNaN(options.aspectRatio)); + + action = cropper.dragBox.dataset.action; + cropper.setDragMode('none'); + assert.strictEqual(cropper.dragBox.dataset.action, action); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/enable.js b/library/cropperjs/test/methods/enable.js new file mode 100644 index 000000000..ebd5b9529 --- /dev/null +++ b/library/cropperjs/test/methods/enable.js @@ -0,0 +1,23 @@ +QUnit.test('methods#enable', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + cropper.disable(); + assert.ok(cropper.disabled); + assert.ok(util.hasClass(cropper.cropper, 'cropper-disabled')); + + cropper.enable(); + assert.notOk(cropper.disabled); + assert.notOk(util.hasClass(cropper.cropper, 'cropper-disabled')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/getCanvasData.js b/library/cropperjs/test/methods/getCanvasData.js new file mode 100644 index 000000000..60d96af4e --- /dev/null +++ b/library/cropperjs/test/methods/getCanvasData.js @@ -0,0 +1,23 @@ +QUnit.test('methods#getCanvasData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(6); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + + assert.ok(util.isNumber(canvasData.left)); + assert.ok(util.isNumber(canvasData.top)); + assert.ok(util.isNumber(canvasData.width)); + assert.ok(util.isNumber(canvasData.height)); + assert.ok(util.isNumber(canvasData.naturalWidth)); + assert.ok(util.isNumber(canvasData.naturalHeight)); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/getContainerData.js b/library/cropperjs/test/methods/getContainerData.js new file mode 100644 index 000000000..094421ba0 --- /dev/null +++ b/library/cropperjs/test/methods/getContainerData.js @@ -0,0 +1,19 @@ +QUnit.test('methods#getContainerData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var containerData = cropper.getContainerData(); + + assert.ok(util.isNumber(containerData.width)); + assert.ok(util.isNumber(containerData.height)); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/getCropBoxData.js b/library/cropperjs/test/methods/getCropBoxData.js new file mode 100644 index 000000000..844c7953e --- /dev/null +++ b/library/cropperjs/test/methods/getCropBoxData.js @@ -0,0 +1,21 @@ +QUnit.test('methods#getCropBoxData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var cropBoxData = cropper.getCropBoxData(); + + assert.ok(util.isNumber(cropBoxData.left)); + assert.ok(util.isNumber(cropBoxData.top)); + assert.ok(util.isNumber(cropBoxData.width)); + assert.ok(util.isNumber(cropBoxData.height)); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/getCroppedCanvas.js b/library/cropperjs/test/methods/getCroppedCanvas.js new file mode 100644 index 000000000..4117497a5 --- /dev/null +++ b/library/cropperjs/test/methods/getCroppedCanvas.js @@ -0,0 +1,33 @@ +QUnit.test('methods#getCroppedCanvas', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(7); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvas = cropper.getCroppedCanvas({ + width: 160, + height: 90 + }); + var pixelData; + + assert.ok(canvas instanceof HTMLCanvasElement); + assert.strictEqual(canvas.width, 160); + assert.strictEqual(canvas.height, 90); + + canvas = cropper.rotate(90).getCroppedCanvas({ + fillColor: '#010101' + }); + pixelData = canvas.getContext('2d').getImageData(0, 0, 1, 1).data; + assert.strictEqual(pixelData[0], 1, 'red is 1'); + assert.strictEqual(pixelData[1], 1, 'green is 1'); + assert.strictEqual(pixelData[2], 1, 'blue is 1'); + assert.strictEqual(pixelData[3], 255, 'color is opaque'); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/getData.js b/library/cropperjs/test/methods/getData.js new file mode 100644 index 000000000..9c519eb7f --- /dev/null +++ b/library/cropperjs/test/methods/getData.js @@ -0,0 +1,46 @@ +QUnit.test('methods#getData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(7); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var data = cropper.getData(); + + assert.ok(util.isNumber(data.x)); + assert.ok(util.isNumber(data.y)); + assert.ok(util.isNumber(data.width)); + assert.ok(util.isNumber(data.height)); + assert.ok(util.isNumber(data.rotate)); + assert.ok(util.isNumber(data.scaleX)); + assert.ok(util.isNumber(data.scaleY)); + + done(); + } + }); +}); + +QUnit.test('methods#getData: rounded', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var data = cropper.getData(true); + + assert.ok(data.x % 1 === 0); + assert.ok(data.y % 1 === 0); + assert.ok(data.width % 1 === 0); + assert.ok(data.height % 1 === 0); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/getImageData.js b/library/cropperjs/test/methods/getImageData.js new file mode 100644 index 000000000..bd6e1941d --- /dev/null +++ b/library/cropperjs/test/methods/getImageData.js @@ -0,0 +1,31 @@ +QUnit.test('methods#getImageData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(10); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var imageData = cropper.getImageData(); + + assert.ok(util.isNumber(imageData.naturalWidth)); + assert.ok(util.isNumber(imageData.naturalHeight)); + assert.ok(util.isNumber(imageData.aspectRatio)); + assert.ok(util.isNumber(imageData.left)); + assert.ok(util.isNumber(imageData.top)); + assert.ok(util.isNumber(imageData.width)); + assert.ok(util.isNumber(imageData.height)); + + imageData = cropper.rotateTo(45).getImageData(); + assert.strictEqual(imageData.rotate, 45); + + imageData = cropper.scale(-1, -1).getImageData(); + assert.strictEqual(imageData.scaleX, -1); + assert.strictEqual(imageData.scaleY, -1); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/move.js b/library/cropperjs/test/methods/move.js new file mode 100644 index 000000000..c2ead8412 --- /dev/null +++ b/library/cropperjs/test/methods/move.js @@ -0,0 +1,20 @@ +QUnit.test('methods#move', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var changedCanvasData = cropper.move(1, 1).getCanvasData(); + + assert.strictEqual(changedCanvasData.left, canvasData.left + 1); + assert.strictEqual(changedCanvasData.top, canvasData.top + 1); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/moveTo.js b/library/cropperjs/test/methods/moveTo.js new file mode 100644 index 000000000..e8bf0eebd --- /dev/null +++ b/library/cropperjs/test/methods/moveTo.js @@ -0,0 +1,19 @@ +QUnit.test('methods#moveTo', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.moveTo(0, 0).getCanvasData(); + + assert.strictEqual(canvasData.left, 0); + assert.strictEqual(canvasData.top, 0); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/replace.js b/library/cropperjs/test/methods/replace.js new file mode 100644 index 000000000..3fc8fe0b6 --- /dev/null +++ b/library/cropperjs/test/methods/replace.js @@ -0,0 +1,23 @@ +QUnit.test('methods#replace', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + cropper.options.ready = function () { + assert.notOk(cropper.cropped); + cropper.crop(); + assert.ok(cropper.cropped); + done(); + }; + + cropper.options.autoCrop = false; + cropper.replace('../docs/images/picture-2.jpg'); + } + }); +}); diff --git a/library/cropperjs/test/methods/reset.js b/library/cropperjs/test/methods/reset.js new file mode 100644 index 000000000..3e047394c --- /dev/null +++ b/library/cropperjs/test/methods/reset.js @@ -0,0 +1,35 @@ +QUnit.test('methods#reset', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var cropBoxData = cropper.getCropBoxData(); + + cropper.setCanvasData({ + top: canvasData.top + 10, + width: canvasData.width - 10 + }); + + assert.notDeepEqual(cropper.getCanvasData(), canvasData); + + cropper.setCropBoxData({ + left: cropBoxData.left + 10, + height: cropBoxData.height - 10 + }); + + assert.notDeepEqual(cropper.getCropBoxData(), cropBoxData); + + cropper.reset(); + assert.deepEqual(cropper.getCanvasData(), canvasData); + assert.deepEqual(cropper.getCropBoxData(), cropBoxData); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/rotate.js b/library/cropperjs/test/methods/rotate.js new file mode 100644 index 000000000..749096f0b --- /dev/null +++ b/library/cropperjs/test/methods/rotate.js @@ -0,0 +1,19 @@ +QUnit.test('methods#rotate', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(3); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.rotate(360).getImageData().rotate, 0); + assert.strictEqual(cropper.rotate(90).getImageData().rotate, 90); + assert.strictEqual(cropper.rotate(-180).getImageData().rotate, -90); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/rotateTo.js b/library/cropperjs/test/methods/rotateTo.js new file mode 100644 index 000000000..323431e76 --- /dev/null +++ b/library/cropperjs/test/methods/rotateTo.js @@ -0,0 +1,20 @@ +QUnit.test('methods#rotateTo', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.rotateTo(360).getImageData().rotate, 0); + assert.strictEqual(cropper.rotateTo(90).getImageData().rotate, 90); + assert.strictEqual(cropper.rotateTo(0).getImageData().rotate, 0); + assert.strictEqual(cropper.rotateTo(-180).getImageData().rotate, -180); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/scale.js b/library/cropperjs/test/methods/scale.js new file mode 100644 index 000000000..be1caa589 --- /dev/null +++ b/library/cropperjs/test/methods/scale.js @@ -0,0 +1,19 @@ +QUnit.test('methods#scale', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var imageData = cropper.scale(-1, -1).getImageData(); + + assert.strictEqual(imageData.scaleX, -1); + assert.strictEqual(imageData.scaleY, -1); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/scaleX.js b/library/cropperjs/test/methods/scaleX.js new file mode 100644 index 000000000..c799df58d --- /dev/null +++ b/library/cropperjs/test/methods/scaleX.js @@ -0,0 +1,18 @@ +QUnit.test('methods#scaleX', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var imageData = cropper.scaleX(-1).getImageData(); + + assert.strictEqual(imageData.scaleX, -1); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/scaleY.js b/library/cropperjs/test/methods/scaleY.js new file mode 100644 index 000000000..026b93a1f --- /dev/null +++ b/library/cropperjs/test/methods/scaleY.js @@ -0,0 +1,18 @@ +QUnit.test('methods#scaleY', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var imageData = cropper.scaleY(-1).getImageData(); + + assert.strictEqual(imageData.scaleY, -1); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/setAspectRatio.js b/library/cropperjs/test/methods/setAspectRatio.js new file mode 100644 index 000000000..ddf46798d --- /dev/null +++ b/library/cropperjs/test/methods/setAspectRatio.js @@ -0,0 +1,20 @@ +QUnit.test('methods#setAspectRatio', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var options = cropper.options; + + assert.ok(isNaN(options.aspectRatio)); + cropper.setAspectRatio(1); + assert.strictEqual(options.aspectRatio, 1); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/setCanvasData.js b/library/cropperjs/test/methods/setCanvasData.js new file mode 100644 index 000000000..e8f6511dc --- /dev/null +++ b/library/cropperjs/test/methods/setCanvasData.js @@ -0,0 +1,34 @@ +QUnit.test('methods#setCanvasData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(6); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var changedCanvasData = cropper.setCanvasData({ + left: 16, + top: 9 + }).getCanvasData(); + + assert.notStrictEqual(changedCanvasData.left, canvasData.left); + assert.notStrictEqual(changedCanvasData.top, canvasData.top); + assert.strictEqual(changedCanvasData.width, canvasData.width); + assert.strictEqual(changedCanvasData.height, canvasData.height); + + canvasData = cropper.getCanvasData(); + changedCanvasData = cropper.setCanvasData({ + width: 320, + height: 180 + }).getCanvasData(); + + assert.notStrictEqual(changedCanvasData.width, canvasData.width); + assert.notStrictEqual(changedCanvasData.height, canvasData.height); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/setCropBoxData.js b/library/cropperjs/test/methods/setCropBoxData.js new file mode 100644 index 000000000..e78767cfc --- /dev/null +++ b/library/cropperjs/test/methods/setCropBoxData.js @@ -0,0 +1,36 @@ +QUnit.test('methods#setCropBoxData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(8); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var cropBoxData = cropper.getCropBoxData(); + var changedCropBoxData = cropper.setCropBoxData({ + left: 16, + top: 9 + }).getCropBoxData(); + + assert.notStrictEqual(changedCropBoxData.left, cropBoxData.left); + assert.notStrictEqual(changedCropBoxData.top, cropBoxData.top); + assert.strictEqual(changedCropBoxData.width, cropBoxData.width); + assert.strictEqual(changedCropBoxData.height, cropBoxData.height); + + cropBoxData = cropper.getCropBoxData(); + changedCropBoxData = cropper.setCropBoxData({ + width: 320, + height: 180 + }).getCropBoxData(); + + assert.strictEqual(changedCropBoxData.left, cropBoxData.left); + assert.strictEqual(changedCropBoxData.top, cropBoxData.top); + assert.notStrictEqual(changedCropBoxData.width, cropBoxData.width); + assert.notStrictEqual(changedCropBoxData.height, cropBoxData.height); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/setData.js b/library/cropperjs/test/methods/setData.js new file mode 100644 index 000000000..4e1360f09 --- /dev/null +++ b/library/cropperjs/test/methods/setData.js @@ -0,0 +1,36 @@ +QUnit.test('methods#setData', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(8); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var data = cropper.getData(); + var changedData = cropper.setData({ + x: 16, + y: 9 + }).getData(); + + assert.notStrictEqual(changedData.x, data.x); + assert.notStrictEqual(changedData.y, data.y); + assert.strictEqual(changedData.width, data.width); + assert.strictEqual(changedData.height, data.height); + + data = cropper.getData(); + changedData = cropper.setData({ + width: 320, + height: 180 + }).getData(); + + assert.strictEqual(changedData.x, data.x); + assert.strictEqual(changedData.y, data.y); + assert.notStrictEqual(changedData.width, data.width); + assert.notStrictEqual(changedData.height, data.height); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/setDragMode.js b/library/cropperjs/test/methods/setDragMode.js new file mode 100644 index 000000000..1b611af9b --- /dev/null +++ b/library/cropperjs/test/methods/setDragMode.js @@ -0,0 +1,27 @@ +QUnit.test('methods#setDragMode', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var dragBox = cropper.dragBox; + + assert.strictEqual(dragBox.dataset.action, 'crop'); + + cropper.setDragMode('move'); + assert.strictEqual(dragBox.dataset.action, 'move'); + + cropper.setDragMode('crop'); + assert.strictEqual(dragBox.dataset.action, 'crop'); + + cropper.setDragMode('none'); + assert.strictEqual(dragBox.dataset.action, 'none'); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/zoom.js b/library/cropperjs/test/methods/zoom.js new file mode 100644 index 000000000..70a1a763a --- /dev/null +++ b/library/cropperjs/test/methods/zoom.js @@ -0,0 +1,20 @@ +QUnit.test('methods#zoom', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var changedCanvasData = cropper.zoom(0.1).getCanvasData(); + + assert.ok(changedCanvasData.width > canvasData.width); + assert.ok(changedCanvasData.height > canvasData.height); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/methods/zoomTo.js b/library/cropperjs/test/methods/zoomTo.js new file mode 100644 index 000000000..dd9e81760 --- /dev/null +++ b/library/cropperjs/test/methods/zoomTo.js @@ -0,0 +1,21 @@ +QUnit.test('methods#zoomTo', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(3); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var imageData = cropper.zoomTo(1).getImageData(); + var canvasData = cropper.getCanvasData(); + + assert.strictEqual(imageData.width, imageData.naturalWidth); + assert.strictEqual(canvasData.width, canvasData.naturalWidth); + assert.strictEqual(canvasData.naturalWidth, imageData.naturalWidth); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/aspectRatio.js b/library/cropperjs/test/options/aspectRatio.js new file mode 100644 index 000000000..d7ba89401 --- /dev/null +++ b/library/cropperjs/test/options/aspectRatio.js @@ -0,0 +1,39 @@ +QUnit.test('options#aspectRatio: NaN', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // aspectRatio: NaN, + + ready: function () { + var cropper = this.cropper; + + assert.ok(isNaN(cropper.options.aspectRatio)); + + done(); + } + }); +}); + +QUnit.test('options#aspectRatio: 1', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + aspectRatio: 1, + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.options.aspectRatio, 1); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/autoCrop.js b/library/cropperjs/test/options/autoCrop.js new file mode 100644 index 000000000..f010966eb --- /dev/null +++ b/library/cropperjs/test/options/autoCrop.js @@ -0,0 +1,39 @@ +QUnit.test('options#autoCrop: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // autoCrop: true, + + ready: function () { + var cropper = this.cropper; + + assert.ok(cropper.cropped); + + done(); + } + }); +}); + +QUnit.test('options#autoCrop: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + autoCrop: false, + + ready: function () { + var cropper = this.cropper; + + assert.notOk(cropper.cropped); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/background.js b/library/cropperjs/test/options/background.js new file mode 100644 index 000000000..21dbb8b12 --- /dev/null +++ b/library/cropperjs/test/options/background.js @@ -0,0 +1,40 @@ +QUnit.test('options#background: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // background: true, + + ready: function () { + var cropper = this.cropper; + + assert.ok(util.hasClass(cropper.cropper, 'cropper-bg')); + + done(); + } + }); +}); + +QUnit.test('options#background: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + background: false, + + ready: function () { + var cropper = this.cropper; + + assert.notOk(util.hasClass(cropper.cropper, 'cropper-bg')); + + done(); + } + }); + +}); diff --git a/library/cropperjs/test/options/center.js b/library/cropperjs/test/options/center.js new file mode 100644 index 000000000..5d45eb021 --- /dev/null +++ b/library/cropperjs/test/options/center.js @@ -0,0 +1,41 @@ +QUnit.test('options#center: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // center: true, + + ready: function () { + var cropper = this.cropper; + var center = util.getByClass(cropper.cropBox, 'cropper-center'); + + assert.notOk(util.hasClass(center[0], 'cropper-hidden')); + + done(); + } + }); +}); + +QUnit.test('options#center: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + center: false, + + ready: function () { + var cropper = this.cropper; + var center = util.getByClass(cropper.cropBox, 'cropper-center'); + + assert.ok(util.hasClass(center[0], 'cropper-hidden')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/checkCrossOrigin.js b/library/cropperjs/test/options/checkCrossOrigin.js new file mode 100644 index 000000000..86fde8f6f --- /dev/null +++ b/library/cropperjs/test/options/checkCrossOrigin.js @@ -0,0 +1,67 @@ +QUnit.test('options#checkCrossOrigin: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage({ + src: 'https://fengyuanchen.github.io/cropperjs/images/picture.jpg' + }); + + assert.expect(2); + + return new Cropper(image, { + // checkCrossOrigin: true, + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.image.crossOrigin, 'anonymous'); + assert.ok(cropper.image.src.indexOf('timestamp') >= 0); + + done(); + } + }); +}); + +QUnit.test('options#checkCrossOrigin: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage({ + src: 'https://fengyuanchen.github.io/cropperjs/images/picture.jpg' + }); + + assert.expect(2); + + return new Cropper(image, { + checkCrossOrigin: false, + + ready: function () { + var cropper = this.cropper; + + assert.notStrictEqual(cropper.image.crossOrigin, 'anonymous'); + assert.ok(cropper.image.src.indexOf('timestamp') < 0); + + done(); + } + }); +}); + +QUnit.test('options#checkCrossOrigin: exists crossOrigin attribute', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage({ + src: 'https://fengyuanchen.github.io/cropperjs/images/picture.jpg', + crossOrigin: 'anonymous' + }); + + assert.expect(2); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.image.crossOrigin, 'anonymous'); + assert.ok(cropper.image.src.indexOf('timestamp') < 0); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/checkOrientation.js b/library/cropperjs/test/options/checkOrientation.js new file mode 100644 index 000000000..0fe548404 --- /dev/null +++ b/library/cropperjs/test/options/checkOrientation.js @@ -0,0 +1,43 @@ +QUnit.test('options#checkOrientation: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage({ + src: '../docs/images/picture-3.jpg' + }); + + assert.expect(1); + + return new Cropper(image, { + // checkOrientation: true, + + ready: function () { + var cropper = this.cropper; + + assert.notStrictEqual(cropper.getData().rotate, 0); + + done(); + } + }); +}); + +QUnit.test('options#checkOrientation: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage({ + src: '../docs/images/picture-3.jpg' + }); + + assert.expect(1); + + return new Cropper(image, { + checkOrientation: false, + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.getData().rotate, 0); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/crop.js b/library/cropperjs/test/options/crop.js new file mode 100644 index 000000000..a4b48585e --- /dev/null +++ b/library/cropperjs/test/options/crop.js @@ -0,0 +1,21 @@ +QUnit.test('options#crop', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(7); + + return new Cropper(image, { + crop: function (e) { + assert.ok(util.isNumber(e.detail.x)); + assert.ok(util.isNumber(e.detail.y)); + assert.ok(util.isNumber(e.detail.width)); + assert.ok(util.isNumber(e.detail.height)); + assert.ok(util.isNumber(e.detail.rotate)); + assert.ok(util.isNumber(e.detail.scaleX)); + assert.ok(util.isNumber(e.detail.scaleY)); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/cropBoxMovable.js b/library/cropperjs/test/options/cropBoxMovable.js new file mode 100644 index 000000000..d5d3e1d7d --- /dev/null +++ b/library/cropperjs/test/options/cropBoxMovable.js @@ -0,0 +1,41 @@ +QUnit.test('options#cropBoxMovable: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // cropBoxMovable: true, + + ready: function () { + var cropper = this.cropper; + var face = util.getByClass(cropper.cropBox, 'cropper-face'); + + assert.strictEqual(face[0].dataset.action, 'all'); + + done(); + } + }); +}); + +QUnit.test('options#cropBoxMovable: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + cropBoxMovable: false, + + ready: function () { + var cropper = this.cropper; + var face = util.getByClass(cropper.cropBox, 'cropper-face'); + + assert.strictEqual(face[0].dataset.action, cropper.options.dragMode); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/cropBoxResizable.js b/library/cropperjs/test/options/cropBoxResizable.js new file mode 100644 index 000000000..37093642b --- /dev/null +++ b/library/cropperjs/test/options/cropBoxResizable.js @@ -0,0 +1,65 @@ +QUnit.test('options#cropBoxResizable: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(12); + + return new Cropper(image, { + // cropBoxResizable: true, + + ready: function () { + var cropper = this.cropper; + var line = util.getByClass(cropper.cropBox, 'cropper-line'); + var point = util.getByClass(cropper.cropBox, 'cropper-point'); + + assert.notOk(util.hasClass(line[0], 'cropper-hidden')); + assert.notOk(util.hasClass(line[1], 'cropper-hidden')); + assert.notOk(util.hasClass(line[2], 'cropper-hidden')); + assert.notOk(util.hasClass(line[3], 'cropper-hidden')); + assert.notOk(util.hasClass(point[0], 'cropper-hidden')); + assert.notOk(util.hasClass(point[1], 'cropper-hidden')); + assert.notOk(util.hasClass(point[2], 'cropper-hidden')); + assert.notOk(util.hasClass(point[3], 'cropper-hidden')); + assert.notOk(util.hasClass(point[4], 'cropper-hidden')); + assert.notOk(util.hasClass(point[5], 'cropper-hidden')); + assert.notOk(util.hasClass(point[6], 'cropper-hidden')); + assert.notOk(util.hasClass(point[7], 'cropper-hidden')); + + done(); + } + }); +}); + +QUnit.test('options#cropBoxResizable: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(12); + + return new Cropper(image, { + cropBoxResizable: false, + + ready: function () { + var cropper = this.cropper; + var line = util.getByClass(cropper.cropBox, 'cropper-line'); + var point = util.getByClass(cropper.cropBox, 'cropper-point'); + + assert.ok(util.hasClass(line[0], 'cropper-hidden')); + assert.ok(util.hasClass(line[1], 'cropper-hidden')); + assert.ok(util.hasClass(line[2], 'cropper-hidden')); + assert.ok(util.hasClass(line[3], 'cropper-hidden')); + assert.ok(util.hasClass(point[0], 'cropper-hidden')); + assert.ok(util.hasClass(point[1], 'cropper-hidden')); + assert.ok(util.hasClass(point[2], 'cropper-hidden')); + assert.ok(util.hasClass(point[3], 'cropper-hidden')); + assert.ok(util.hasClass(point[4], 'cropper-hidden')); + assert.ok(util.hasClass(point[5], 'cropper-hidden')); + assert.ok(util.hasClass(point[6], 'cropper-hidden')); + assert.ok(util.hasClass(point[7], 'cropper-hidden')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/cropend.js b/library/cropperjs/test/options/cropend.js new file mode 100644 index 000000000..abfe815c0 --- /dev/null +++ b/library/cropperjs/test/options/cropend.js @@ -0,0 +1,24 @@ +QUnit.test('options#cropend', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + ready: function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointermove' : 'mousemove'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }, + + cropend: function (e) { + assert.strictEqual(e.detail.action, 'crop'); + } + }); +}); diff --git a/library/cropperjs/test/options/cropmove.js b/library/cropperjs/test/options/cropmove.js new file mode 100644 index 000000000..fa20f4011 --- /dev/null +++ b/library/cropperjs/test/options/cropmove.js @@ -0,0 +1,24 @@ +QUnit.test('options#cropmove', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + ready: function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointermove' : 'mousemove'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }, + + cropmove: function (e) { + assert.strictEqual(e.detail.action, 'crop'); + } + }); +}); diff --git a/library/cropperjs/test/options/cropstart.js b/library/cropperjs/test/options/cropstart.js new file mode 100644 index 000000000..f547269cd --- /dev/null +++ b/library/cropperjs/test/options/cropstart.js @@ -0,0 +1,56 @@ +QUnit.test('options#cropstart', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + ready: function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }, + + cropstart: function (e) { + assert.strictEqual(e.detail.action, 'crop'); + } + }); +}); + +QUnit.test('options#cropstart: default prevented', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(0); + + return new Cropper(image, { + ready: function () { + var PointerEvent = window.PointerEvent; + var cropper = this.cropper; + + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerdown' : 'mousedown'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointermove' : 'mousemove'); + util.dispatchEvent(cropper.dragBox, PointerEvent ? 'pointerup' : 'mouseup'); + + done(); + }, + + cropstart: function (e) { + e.preventDefault(); + }, + + cropmove: function () { + assert.ok(false); + }, + + cropend: function () { + assert.ok(false); + } + }); +}); diff --git a/library/cropperjs/test/options/data.js b/library/cropperjs/test/options/data.js new file mode 100644 index 000000000..e9da6a4dd --- /dev/null +++ b/library/cropperjs/test/options/data.js @@ -0,0 +1,35 @@ +QUnit.test('options#data', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + var initialData = { + x: 360, + y: 450, + width: 640, + height: 360, + rotate: 45, + scaleX: -1, + scaleY: -1 + }; + + assert.expect(7); + + return new Cropper(image, { + data: initialData, + + ready: function () { + var cropper = this.cropper; + var data = cropper.getData(true); + + assert.strictEqual(data.x, initialData.x); + assert.strictEqual(data.y, initialData.y); + assert.strictEqual(data.width, initialData.width); + assert.strictEqual(data.height, initialData.height); + assert.strictEqual(data.rotate, initialData.rotate); + assert.strictEqual(data.scaleX, initialData.scaleX); + assert.strictEqual(data.scaleY, initialData.scaleY); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/dragMode.js b/library/cropperjs/test/options/dragMode.js new file mode 100644 index 000000000..57f31ff13 --- /dev/null +++ b/library/cropperjs/test/options/dragMode.js @@ -0,0 +1,60 @@ +QUnit.test('options#dragMode: crop', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // dragMode: 'crop', + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.dragBox.dataset.action, 'crop'); + + done(); + } + }); +}); + +QUnit.test('options#dragMode: move', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + dragMode: 'move', + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.dragBox.dataset.action, 'move'); + + done(); + } + }); +}); + + +QUnit.test('options#dragMode: none', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + dragMode: 'none', + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.dragBox.dataset.action, 'none'); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/guides.js b/library/cropperjs/test/options/guides.js new file mode 100644 index 000000000..298c3ad3a --- /dev/null +++ b/library/cropperjs/test/options/guides.js @@ -0,0 +1,43 @@ +QUnit.test('options#guides: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + // guides: true, + + ready: function () { + var cropper = this.cropper; + var dashed = util.getByClass(cropper.cropBox, 'cropper-dashed'); + + assert.notOk(util.hasClass(dashed[0], 'cropper-hidden')); + assert.notOk(util.hasClass(dashed[1], 'cropper-hidden')); + + done(); + } + }); +}); + +QUnit.test('options#guides: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + guides: false, + + ready: function () { + var cropper = this.cropper; + var dashed = util.getByClass(cropper.cropBox, 'cropper-dashed'); + + assert.ok(util.hasClass(dashed[0], 'cropper-hidden')); + assert.ok(util.hasClass(dashed[1], 'cropper-hidden')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/highlight.js b/library/cropperjs/test/options/highlight.js new file mode 100644 index 000000000..a1db4687f --- /dev/null +++ b/library/cropperjs/test/options/highlight.js @@ -0,0 +1,41 @@ +QUnit.test('options#highlight: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // highlight: true, + + ready: function () { + var cropper = this.cropper; + var face = util.getByClass(cropper.cropBox, 'cropper-face'); + + assert.notOk(util.hasClass(face[0], 'cropper-invisible')); + + done(); + } + }); +}); + +QUnit.test('options#highlight: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + highlight: false, + + ready: function () { + var cropper = this.cropper; + var face = util.getByClass(cropper.cropBox, 'cropper-face'); + + assert.ok(util.hasClass(face[0], 'cropper-invisible')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/minCanvasHeight.js b/library/cropperjs/test/options/minCanvasHeight.js new file mode 100644 index 000000000..c9745a9b1 --- /dev/null +++ b/library/cropperjs/test/options/minCanvasHeight.js @@ -0,0 +1,23 @@ +QUnit.test('options#minCanvasHeight', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + var minCanvasHeight = 270; + + assert.expect(1); + + return new Cropper(image, { + minCanvasHeight: minCanvasHeight, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.setCanvasData({ + height: 180 + }).getCanvasData(); + + assert.strictEqual(Math.round(canvasData.height), minCanvasHeight); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/minCanvasWidth.js b/library/cropperjs/test/options/minCanvasWidth.js new file mode 100644 index 000000000..61601e4f9 --- /dev/null +++ b/library/cropperjs/test/options/minCanvasWidth.js @@ -0,0 +1,23 @@ +QUnit.test('options#minCanvasWidth', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + var minCanvasWidth = 480; + + assert.expect(1); + + return new Cropper(image, { + minCanvasWidth: minCanvasWidth, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.setCanvasData({ + width: 320 + }).getCanvasData(); + + assert.strictEqual(Math.round(canvasData.width), minCanvasWidth); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/minContainerHeight.js b/library/cropperjs/test/options/minContainerHeight.js new file mode 100644 index 000000000..85d7a70ef --- /dev/null +++ b/library/cropperjs/test/options/minContainerHeight.js @@ -0,0 +1,21 @@ +QUnit.test('options#minContainerHeight', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + var minContainerHeight = 361; + + assert.expect(1); + + return new Cropper(image, { + minContainerHeight: minContainerHeight, + + ready: function () { + var cropper = this.cropper; + var containerData = cropper.getContainerData(); + + assert.strictEqual(Math.round(containerData.height), minContainerHeight); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/minContainerWidth.js b/library/cropperjs/test/options/minContainerWidth.js new file mode 100644 index 000000000..2119cc96e --- /dev/null +++ b/library/cropperjs/test/options/minContainerWidth.js @@ -0,0 +1,21 @@ +QUnit.test('options#minContainerWidth', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + var minContainerWidth = 641; + + assert.expect(1); + + return new Cropper(image, { + minContainerWidth: minContainerWidth, + + ready: function () { + var cropper = this.cropper; + var containerData = cropper.getContainerData(); + + assert.strictEqual(Math.round(containerData.width), minContainerWidth); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/minCropBoxHeight.js b/library/cropperjs/test/options/minCropBoxHeight.js new file mode 100644 index 000000000..ccf50aefe --- /dev/null +++ b/library/cropperjs/test/options/minCropBoxHeight.js @@ -0,0 +1,23 @@ +QUnit.test('options#minCropBoxHeight', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + var minCropBoxHeight = 150; + + assert.expect(1); + + return new Cropper(image, { + minCropBoxHeight: minCropBoxHeight, + + ready: function () { + var cropper = this.cropper; + var cropBoxData = cropper.setCropBoxData({ + height: 100 + }).getCropBoxData(); + + assert.strictEqual(Math.round(cropBoxData.height), minCropBoxHeight); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/minCropBoxWidth.js b/library/cropperjs/test/options/minCropBoxWidth.js new file mode 100644 index 000000000..acde5c366 --- /dev/null +++ b/library/cropperjs/test/options/minCropBoxWidth.js @@ -0,0 +1,23 @@ +QUnit.test('options#minCropBoxWidth', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + var minCropBoxWidth = 300; + + assert.expect(1); + + return new Cropper(image, { + minCropBoxWidth: minCropBoxWidth, + + ready: function () { + var cropper = this.cropper; + var cropBoxData = cropper.setCropBoxData({ + width: 200 + }).getCropBoxData(); + + assert.strictEqual(Math.round(cropBoxData.width), minCropBoxWidth); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/modal.js b/library/cropperjs/test/options/modal.js new file mode 100644 index 000000000..7284cb264 --- /dev/null +++ b/library/cropperjs/test/options/modal.js @@ -0,0 +1,39 @@ +QUnit.test('options#modal: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // modal: true, + + ready: function () { + var cropper = this.cropper; + + assert.ok(util.hasClass(cropper.dragBox, 'cropper-modal')); + + done(); + } + }); +}); + +QUnit.test('options#modal: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + modal: false, + + ready: function () { + var cropper = this.cropper; + + assert.notOk(util.hasClass(cropper.dragBox, 'cropper-modal')); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/movable.js b/library/cropperjs/test/options/movable.js new file mode 100644 index 000000000..0e2c53506 --- /dev/null +++ b/library/cropperjs/test/options/movable.js @@ -0,0 +1,45 @@ +QUnit.test('options#movable: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + // movable: true, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var changedCanvasData = cropper.move(10, 10).getCanvasData(); + + assert.strictEqual(changedCanvasData.left, canvasData.left + 10); + assert.strictEqual(changedCanvasData.top, canvasData.top + 10); + + done(); + } + }); +}); + +QUnit.test('options#movable: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + movable: false, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var changedCanvasData = cropper.move(10, 10).getCanvasData(); + + assert.strictEqual(changedCanvasData.left, canvasData.left); + assert.strictEqual(changedCanvasData.top, canvasData.top); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/ready.js b/library/cropperjs/test/options/ready.js new file mode 100644 index 000000000..e09e8369c --- /dev/null +++ b/library/cropperjs/test/options/ready.js @@ -0,0 +1,15 @@ +QUnit.test('options#ready', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + ready: function () { + assert.ok(true); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/rotatable.js b/library/cropperjs/test/options/rotatable.js new file mode 100644 index 000000000..992e9362f --- /dev/null +++ b/library/cropperjs/test/options/rotatable.js @@ -0,0 +1,39 @@ +QUnit.test('options#rotatable: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // rotatable: true, + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.rotate(90).getImageData().rotate, 90); + + done(); + } + }); +}); + +QUnit.test('options#rotatable: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + rotatable: false, + + ready: function () { + var cropper = this.cropper; + + assert.strictEqual(cropper.rotate(90).getImageData().rotate, undefined); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/scalable.js b/library/cropperjs/test/options/scalable.js new file mode 100644 index 000000000..c523eaf63 --- /dev/null +++ b/library/cropperjs/test/options/scalable.js @@ -0,0 +1,43 @@ +QUnit.test('options#scalable: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + // scalable: true, + + ready: function () { + var cropper = this.cropper; + var imageData = cropper.scale(-1, -1).getImageData(); + + assert.strictEqual(imageData.scaleX, -1); + assert.strictEqual(imageData.scaleY, -1); + + done(); + } + }); +}); + +QUnit.test('options#scalable: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + scalable: false, + + ready: function () { + var cropper = this.cropper; + var imageData = cropper.scale(-1, -1).getImageData(); + + assert.strictEqual(imageData.scaleX, undefined); + assert.strictEqual(imageData.scaleY, undefined); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/toggleDragModeOnDblclick.js b/library/cropperjs/test/options/toggleDragModeOnDblclick.js new file mode 100644 index 000000000..df64327b2 --- /dev/null +++ b/library/cropperjs/test/options/toggleDragModeOnDblclick.js @@ -0,0 +1,45 @@ +QUnit.test('options#toggleDragModeOnDblclick: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + // toggleDragModeOnDblclick: true, + + ready: function () { + var cropper = this.cropper; + var dragBox = cropper.dragBox; + + util.dispatchEvent(dragBox, 'dblclick'); + assert.ok(util.hasClass(dragBox, 'cropper-move')); + assert.strictEqual(dragBox.dataset.action, 'move'); + + done(); + } + }); +}); + +QUnit.test('options#toggleDragModeOnDblclick: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + toggleDragModeOnDblclick: false, + + ready: function () { + var cropper = this.cropper; + var dragBox = cropper.dragBox; + + util.dispatchEvent(dragBox, 'dblclick'); + assert.ok(util.hasClass(dragBox, 'cropper-crop')); + assert.strictEqual(dragBox.dataset.action, 'crop'); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/viewMode.js b/library/cropperjs/test/options/viewMode.js new file mode 100644 index 000000000..e39ec5fc1 --- /dev/null +++ b/library/cropperjs/test/options/viewMode.js @@ -0,0 +1,100 @@ +QUnit.test('options#viewMode: 0', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + // viewMode: 0, + + ready: function () { + var cropper = this.cropper; + var canvasData = { + left: 100, + top: 100, + width: 160, + height: 90 + }; + var changedCanvasData = cropper.setCanvasData(canvasData).getCanvasData(); + + assert.strictEqual(changedCanvasData.left, canvasData.left); + assert.strictEqual(changedCanvasData.top, canvasData.top); + assert.strictEqual(changedCanvasData.width, canvasData.width); + assert.strictEqual(changedCanvasData.height, canvasData.height); + + done(); + } + }); +}); + +QUnit.test('options#viewMode: 1', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + viewMode: 1, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.zoom(-0.5).getCanvasData(); // Zoom out + var cropBoxData = cropper.getCropBoxData(); + + assert.ok(canvasData.width >= cropBoxData.width); + assert.ok(canvasData.height >= cropBoxData.height); + + done(); + } + }); +}); + +QUnit.test('options#viewMode: 2', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + viewMode: 2, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.zoom(-0.5).getCanvasData(); // Zoom out + var containerData = cropper.getContainerData(); + + assert.ok(canvasData.width >= containerData.width || + canvasData.height >= containerData.height); + + done(); + } + }); +}); + +QUnit.test('options#viewMode: 3', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(4); + + return new Cropper(image, { + viewMode: 3, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.zoom(-0.5).getCanvasData(); // Zoom out + var containerData = cropper.getContainerData(); + + assert.ok(canvasData.left <= 0); + assert.ok(canvasData.top <= 0); + assert.ok(canvasData.width >= containerData.width); + assert.ok(canvasData.height >= containerData.height); + + done(); + } + }); +}); diff --git a/library/cropperjs/test/options/zoom.js b/library/cropperjs/test/options/zoom.js new file mode 100644 index 000000000..51ebc76ad --- /dev/null +++ b/library/cropperjs/test/options/zoom.js @@ -0,0 +1,46 @@ +QUnit.test('options#zoom', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(3); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + + cropper.zoom(0.1); + + done(); + }, + + zoom: function (e) { + assert.ok(e.detail.ratio > 0); + assert.ok(e.detail.oldRatio > 0); + assert.ok(e.detail.ratio > e.detail.oldRatio); + } + }); +}); + +QUnit.test('options#zoom: default prevented', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + + assert.deepEqual(cropper.zoom(0.1).getCanvasData(), canvasData); + + done(); + }, + + zoom: function (e) { + e.preventDefault(); + } + }); +}); diff --git a/library/cropperjs/test/options/zoomOnWheel.js b/library/cropperjs/test/options/zoomOnWheel.js new file mode 100644 index 000000000..1a1bf6dce --- /dev/null +++ b/library/cropperjs/test/options/zoomOnWheel.js @@ -0,0 +1,47 @@ +QUnit.test('options#zoomOnWheel: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(1); + + return new Cropper(image, { + // zoomOnWheel: true, + + ready: function () { + var cropper = this.cropper; + + util.dispatchEvent(cropper.cropper, 'wheel'); + + done(); + }, + + zoom: function () { + assert.ok(true); + } + }); +}); + +QUnit.test('options#zoomOnWheel: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(0); + + return new Cropper(image, { + zoomOnWheel: false, + + ready: function () { + var cropper = this.cropper; + + util.dispatchEvent(cropper.cropper, 'wheel'); + + done(); + }, + + zoom: function () { + assert.ok(false); + } + }); +}); diff --git a/library/cropperjs/test/options/zoomable.js b/library/cropperjs/test/options/zoomable.js new file mode 100644 index 000000000..9f8ec6fce --- /dev/null +++ b/library/cropperjs/test/options/zoomable.js @@ -0,0 +1,51 @@ +QUnit.test('options#zoomable: true', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(3); + + return new Cropper(image, { + // zoomable: true, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var changedCanvasData = cropper.zoom(0.1).getCanvasData(); + + assert.ok(changedCanvasData.width > canvasData.width); + assert.ok(changedCanvasData.height > canvasData.height); + + done(); + }, + zoom: function () { + assert.ok(true); + } + }); +}); + +QUnit.test('options#zoomable: false', function (assert) { + var done = assert.async(); + var util = window.Util; + var image = util.createImage(); + + assert.expect(2); + + return new Cropper(image, { + zoomable: false, + + ready: function () { + var cropper = this.cropper; + var canvasData = cropper.getCanvasData(); + var changedCanvasData = cropper.zoom(0.1).getCanvasData(); + + assert.ok(changedCanvasData.width === canvasData.width); + assert.ok(changedCanvasData.height === canvasData.height); + + done(); + }, + zoom: function () { + assert.ok(false); + } + }); +}); From 5d4110375ad053be7d7a28696b725ee2e36eb1e9 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Tue, 23 Jan 2018 16:44:11 -0800 Subject: [PATCH 12/15] add units to css --- Zotlabs/Module/Profile_photo.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php index 3aa6aee79..222b92721 100644 --- a/Zotlabs/Module/Profile_photo.php +++ b/Zotlabs/Module/Profile_photo.php @@ -56,7 +56,7 @@ class Profile_photo extends \Zotlabs\Web\Controller { if((array_key_exists('cropfinal',$_POST)) && (intval($_POST['cropfinal']) == 1)) { - logger('crop: ' . print_r($_POST,true)); + // logger('crop: ' . print_r($_POST,true)); From 304085606fac6ae4fd2d3e29ed44afb4b4e1bc28 Mon Sep 17 00:00:00 2001 From: zotlabs Date: Tue, 23 Jan 2018 20:03:17 -0800 Subject: [PATCH 13/15] some code cleanup and simplification in mod_like --- Zotlabs/Module/Like.php | 81 +++++++++++++++++++++-------------------- boot.php | 1 + 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php index b07824363..6d9fde17c 100644 --- a/Zotlabs/Module/Like.php +++ b/Zotlabs/Module/Like.php @@ -9,9 +9,41 @@ require_once('include/items.php'); class Like extends \Zotlabs\Web\Controller { - function get() { + + + private function reaction_to_activity($reaction) { + + $acts = [ + 'like' => ACTIVITY_LIKE , + 'dislike' => ACTIVITY_DISLIKE , + 'agree' => ACTIVITY_AGREE , + 'disagree' => ACTIVITY_DISAGREE , + 'abstain' => ACTIVITY_ABSTAIN , + 'attendyes' => ACTIVITY_ATTEND , + 'attendno' => ACTIVITY_ATTENDNO , + 'attendmaybe' => ACTIVITY_ATTENDMAYBE + ]; + + // unlike (etc.) reactions are an undo of positive reactions, rather than a negative action. + // The activity is the same in undo actions and will have the same activity mapping + + if(substr($reaction,0,2) === 'un') { + $reaction = substr($reaction,2); + } + + if(array_key_exists($reaction,$acts)) { + return $acts[$reaction]; + } + + return EMPTY_STR; + + } + + + + public function get() { - $o = ''; + $o = EMPTY_STR; $sys_channel = get_sys_channel(); $sys_channel_id = (($sys_channel) ? $sys_channel['channel_id'] : 0); @@ -35,48 +67,17 @@ class Like extends \Zotlabs\Web\Controller { if(! $verb) $verb = 'like'; - switch($verb) { - case 'like': - case 'unlike': - $activity = ACTIVITY_LIKE; - break; - case 'dislike': - case 'undislike': - $activity = ACTIVITY_DISLIKE; - break; - case 'agree': - case 'unagree': - $activity = ACTIVITY_AGREE; - break; - case 'disagree': - case 'undisagree': - $activity = ACTIVITY_DISAGREE; - break; - case 'abstain': - case 'unabstain': - $activity = ACTIVITY_ABSTAIN; - break; - case 'attendyes': - case 'unattendyes': - $activity = ACTIVITY_ATTEND; - break; - case 'attendno': - case 'unattendno': - $activity = ACTIVITY_ATTENDNO; - break; - case 'attendmaybe': - case 'unattendmaybe': - $activity = ACTIVITY_ATTENDMAYBE; - break; - default: - return; - break; + $activity = $this->reaction_to_activity($verb); + + if(! $activity) { + return EMPTY_STR; } + $extended_like = false; $object = $target = null; - $post_type = ''; - $objtype = ''; + $post_type = EMPTY_STR; + $objtype = EMPTY_STR; if(argc() == 3) { diff --git a/boot.php b/boot.php index ece2150e1..39047933d 100755 --- a/boot.php +++ b/boot.php @@ -66,6 +66,7 @@ define ( 'PROJECT_BASE', __DIR__ ); * This can be used in HTML and JavaScript where needed a line break. */ define ( 'EOL', '
    ' . "\r\n" ); +define ( 'EMPTY_STR', '' ); define ( 'ATOM_TIME', 'Y-m-d\\TH:i:s\\Z' ); // aka ISO 8601 "Zulu" define ( 'TEMPLATE_BUILD_PATH', 'store/[data]/smarty3' ); From e3a6b0012e95aae8e0572a53ea96ddc915d6eb03 Mon Sep 17 00:00:00 2001 From: Mario Vavti Date: Wed, 24 Jan 2018 11:16:51 +0100 Subject: [PATCH 14/15] implement caching of notifications in browser session storage --- Zotlabs/Module/Logout.php | 2 +- view/js/main.js | 237 +++++++++++++++++------------- view/tpl/notifications_widget.tpl | 4 +- 3 files changed, 141 insertions(+), 102 deletions(-) diff --git a/Zotlabs/Module/Logout.php b/Zotlabs/Module/Logout.php index 6aa11d110..f06e7278b 100644 --- a/Zotlabs/Module/Logout.php +++ b/Zotlabs/Module/Logout.php @@ -9,4 +9,4 @@ class Logout extends \Zotlabs\Web\Controller { goaway(z_root()); } -} \ No newline at end of file +} diff --git a/view/js/main.js b/view/js/main.js index 034a520e7..00c536243 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -23,6 +23,17 @@ var mediaPlaying = false; var contentHeightDiff = 0; var liveRecurse = 0; var savedTitle = ''; +var initialLoad = true; + +// Clear the session storage if we switch channel or log out +var cache_uid = ''; +if(sessionStorage.getItem('uid') !== null) { + cache_uid = sessionStorage.getItem('uid'); +} +if(cache_uid !== localUser.toString()) { + sessionStorage.clear(); + sessionStorage.setItem('uid', localUser.toString()); +} $.ajaxSetup({cache: false}); @@ -54,9 +65,17 @@ $(document).ready(function() { updateInit(); - $('a[rel^="#"]').click(function(e){ - manage_popup_menu(this, e); - return; + $('a.notification-link').click(function(e){ + var notifyType = $(this).data('type'); + + if (!$(this).data('clicked') && (sessionStorage.getItem(notifyType + '_notifications_cache') !== null)) { + var cached_data = JSON.parse(sessionStorage.getItem(notifyType + '_notifications_cache')); + loadNotificationItems(notifyType, cached_data); + $(this).data('clicked', true); + } + else { + loadNotificationItems(notifyType); + } }); // Allow folks to stop the ajax page updates with the pause/break key @@ -88,7 +107,9 @@ $(document).ready(function() { var e = document.getElementById('content-complete'); if(e) - pageHasMoreContent = false; + pageHasMoreContent = false; + + initialLoad = false; }); @@ -340,75 +361,110 @@ function markItemRead(itemId) { $('.unseen-wall-indicator-'+itemId).hide(); } -function manage_popup_menu(w,e) { - menu = $( $(w).attr('rel') ); - - /* notification menus are loaded dynamically - * - here we find a rel tag to figure out what type of notification to load */ - - var loader_source = $(menu).attr('rel'); - - if(typeof(loader_source) != 'undefined' && loader_source.length) { - notify_popup_loader(loader_source); - } -} - -function notificationsUpdate() { +function notificationsUpdate(cached_data) { var pingCmd = 'ping' + ((localUser != 0) ? '?f=&uid=' + localUser : ''); - $.get(pingCmd,function(data) { + if(cached_data !== undefined) { + handleNotifications(cached_data); + } + else { + $.get(pingCmd,function(data) { - if(data.invalid == 1) { - window.location.href=window.location.href; - } + // Put the object into storage + sessionStorage.setItem('notifications_cache', JSON.stringify(data)); - if(data.network || data.home || data.intros || data.register || data.mail || data.all_events || data.notify || data.files || data.pubs) { - $('.notifications-btn').css('opacity', 1); - $('#no_notifications').hide(); - } - else { - $('.notifications-btn').css('opacity', 0.5); - $('#navbar-collapse-1').removeClass('show'); - $('#no_notifications').show(); - } - - if(data.home || data.intros || data.register || data.mail || data.notify || data.files) { - $('.notifications-btn-icon').removeClass('fa-exclamation-circle'); - $('.notifications-btn-icon').addClass('fa-exclamation-triangle'); - } - if(!data.home && !data.intros && !data.register && !data.mail && !data.notify && !data.files) { - $('.notifications-btn-icon').removeClass('fa-exclamation-triangle'); - $('.notifications-btn-icon').addClass('fa-exclamation-circle'); - } - - $.each(data, function(index, item) { - //do not process those - var arr = ['notice', 'info', 'invalid']; - if(arr.indexOf(index) !== -1) - return; - - if(item == 0) { - $('.' + index + '-button').fadeOut(); - } else { - $('.' + index + '-button').fadeIn(); - $('.' + index + '-update').html(item); + if(data.invalid == 1) { + window.location.href=window.location.href; } - }); - $.jGrowl.defaults.closerTemplate = '
    [ ' + aStr.closeAll + ']
    '; + handleNotifications(data); - $(data.notice).each(function() { - $.jGrowl(this.message, { sticky: true, theme: 'notice' }); - }); + $.jGrowl.defaults.closerTemplate = '
    [ ' + aStr.closeAll + ']
    '; - $(data.info).each(function(){ - $.jGrowl(this.message, { sticky: false, theme: 'info', life: 10000 }); + $(data.notice).each(function() { + $.jGrowl(this.message, { sticky: true, theme: 'notice' }); + }); + + $(data.info).each(function(){ + $.jGrowl(this.message, { sticky: false, theme: 'info', life: 10000 }); + }); }); - }) + } + if(timer) clearTimeout(timer); timer = setTimeout(updateInit,updateInterval); } +function handleNotifications(data) { + if(data.network || data.home || data.intros || data.register || data.mail || data.all_events || data.notify || data.files || data.pubs) { + $('.notifications-btn').css('opacity', 1); + $('#no_notifications').hide(); + } + else { + $('.notifications-btn').css('opacity', 0.5); + $('#navbar-collapse-1').removeClass('show'); + $('#no_notifications').show(); + } + + if(data.home || data.intros || data.register || data.mail || data.notify || data.files) { + $('.notifications-btn-icon').removeClass('fa-exclamation-circle'); + $('.notifications-btn-icon').addClass('fa-exclamation-triangle'); + } + if(!data.home && !data.intros && !data.register && !data.mail && !data.notify && !data.files) { + $('.notifications-btn-icon').removeClass('fa-exclamation-triangle'); + $('.notifications-btn-icon').addClass('fa-exclamation-circle'); + } + + $.each(data, function(index, item) { + //do not process those + var arr = ['notice', 'info', 'invalid']; + if(arr.indexOf(index) !== -1) + return; + + if(item == 0) { + $('.' + index + '-button').fadeOut(); + } else { + $('.' + index + '-button').fadeIn(); + $('.' + index + '-update').html(item); + } + }); +} + +function handleNotificationsItems(notifyType, data) { + + var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html()); + var notify_menu = $("#nav-" + notifyType + "-menu"); + + notify_menu.html(''); + + $(data).each(function() { + html = notifications_tpl.format(this.notify_link,this.photo,this.name,this.message,this.when,this.hclass,this.b64mid,this.notify_id,this.thread_top); + notify_menu.append(html); + }); + + $(".dropdown-menu img[data-src], .notification img[data-src]").each(function(i, el){ + // Replace data-src attribute with src attribute for every image + $(el).attr('src', $(el).data("src")); + $(el).removeAttr("data-src"); + }); + + if($('#tt-' + notifyType + '-only').hasClass('active')) + $('#nav-' + notifyType + '-menu [data-thread_top=false]').hide(); + + if($('#cn-' + notifyType + '-input').length) { + var filter = $('#cn-' + notifyType + '-input').val().toString().toLowerCase(); + if(filter) { + $('#nav-' + notifyType + '-menu .notification').each(function(i, el){ + var cn = $(el).data('contact_name').toString().toLowerCase(); + if(cn.indexOf(filter) === -1) + $(el).addClass('d-none'); + else + $(el).removeClass('d-none'); + }); + } + } +} + function contextualHelp() { var container = $("#contextual-help-content"); @@ -671,6 +727,11 @@ function updateInit() { // if($('#live-cards').length) { src = 'cards'; } // if($('#live-articles').length) { src = 'articles'; } + if (initialLoad && (sessionStorage.getItem('notifications_cache') !== null)) { + var cached_data = JSON.parse(sessionStorage.getItem('notifications_cache')); + notificationsUpdate(cached_data); + } + if(! src) { notificationsUpdate(); } @@ -700,6 +761,9 @@ function liveUpdate(notify_id) { return; } + if(timer) + clearTimeout(timer); + if(livetime !== null) livetime = null; @@ -860,56 +924,31 @@ function justifyPhotosAjax(id) { $('#' + id).justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; }); } -function notify_popup_loader(notifyType) { +function loadNotificationItems(notifyType, cached_data) { - var notifications_tpl= unescape($("#nav-notifications-template[rel=template]").html()); - var notify_menu = $("#nav-" + notifyType + "-menu"); var pingExCmd = 'ping/' + notifyType + ((localUser != 0) ? '?f=&uid=' + localUser : ''); - $.get(pingExCmd, function(data) { + if(cached_data !== undefined) { + handleNotificationsItems(notifyType, cached_data); + } + else { + $.get(pingExCmd, function(data) { + if(data.invalid == 1) { + window.location.href=window.location.href; + } - if(data.invalid == 1) { - window.location.href=window.location.href; - } + $("." + notifyType + "-update").html(data.notify.length); - //$("#navbar-" + notifyType + "-menu").html(notifications_all + notifications_mark + notifications_tt_only + notifications_cn_only); - //$("#nav-" + notifyType + "-menu").html(notifications_all + notifications_mark + notifications_tt_only + notifications_cn_only); + sessionStorage.setItem(notifyType + '_notifications_cache', JSON.stringify(data.notify)); - $("." + notifyType + "-update").html(data.notify.length); - - notify_menu.html(''); - - $(data.notify).each(function() { - html = notifications_tpl.format(this.notify_link,this.photo,this.name,this.message,this.when,this.hclass,this.b64mid,this.notify_id,this.thread_top); - notify_menu.append(html); + handleNotificationsItems(notifyType, data.notify); }); - - $(".dropdown-menu img[data-src], .notification img[data-src]").each(function(i, el){ - // Replace data-src attribute with src attribute for every image - $(el).attr('src', $(el).data("src")); - $(el).removeAttr("data-src"); - }); - - if($('#tt-' + notifyType + '-only').hasClass('active')) - $('#nav-' + notifyType + '-menu [data-thread_top=false]').hide(); - - var filter = $('#cn-' + notifyType + '-input').val().toString().toLowerCase(); - if(filter) { - $('#nav-' + notifyType + '-menu .notification').each(function(i, el){ - var cn = $(el).data('contact_name').toString().toLowerCase(); - if(cn.indexOf(filter) === -1) - $(el).addClass('d-none'); - else - $(el).removeClass('d-none'); - }); - } - }); - + } setTimeout(function() { if($('#nav-' + notifyType + '-sub').hasClass('show')) { console.log('updating ' + notifyType + ' notifications...'); - setTimeout(notify_popup_loader, updateInterval, notifyType); + setTimeout(loadNotificationItems, updateInterval, notifyType); } }, 1000); } diff --git a/view/tpl/notifications_widget.tpl b/view/tpl/notifications_widget.tpl index 6b3f4b15b..fd5c0dbc0 100644 --- a/view/tpl/notifications_widget.tpl +++ b/view/tpl/notifications_widget.tpl @@ -125,7 +125,7 @@ {{foreach $notifications as $notification}}
    - + {{$notification.label}} @@ -149,7 +149,7 @@
    {{/if}} - From add9890754780c886188504647b3058c4cc146c1 Mon Sep 17 00:00:00 2001 From: Mario Vavti Date: Wed, 24 Jan 2018 11:23:45 +0100 Subject: [PATCH 15/15] bump version --- boot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boot.php b/boot.php index 39047933d..42b5ae33e 100755 --- a/boot.php +++ b/boot.php @@ -51,7 +51,7 @@ require_once('include/attach.php'); require_once('include/bbcode.php'); define ( 'PLATFORM_NAME', 'hubzilla' ); -define ( 'STD_VERSION', '3.1.2' ); +define ( 'STD_VERSION', '3.1.3' ); define ( 'ZOT_REVISION', '1.3' ); define ( 'DB_UPDATE_VERSION', 1198 );