├── .babelrc ├── .gitignore ├── LICENSE ├── README.md ├── chrome ├── .keep ├── background.html ├── build │ └── .keep ├── css │ └── insite.css ├── image │ ├── 128x128.png │ ├── icon-l.png │ ├── icon.png │ ├── linkcard │ │ └── scrapbox_default.png │ └── x.png ├── lib │ ├── clipboard.min.js │ ├── images │ │ └── ui-icons_222222_256x240.png │ ├── jquery-ui.min.css │ ├── jquery-ui.min.js │ └── jquery.js ├── manifest.json ├── options.html └── popup.html ├── client ├── background.js ├── common.js ├── content_script.js ├── create_svg.js ├── inline_viewer.js ├── options.js └── popup.js ├── package-lock.json ├── package.json ├── releases └── .keep └── src └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "comments": false 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | fonts/ 3 | dist/* 4 | !dist/.keep 5 | !build/.gitkeep 6 | chrome/build/* 7 | !chrome/build/.keep 8 | releases/* 9 | !releases/.keep 10 | 11 | ### https://raw.github.com/github/gitignore/4db4bb6e20ded299466202bfcb5b07f5cf3325cd/Node.gitignore 12 | 13 | # Logs 14 | logs 15 | *.log 16 | npm-debug.log* 17 | yarn-debug.log* 18 | yarn-error.log* 19 | 20 | # Runtime data 21 | pids 22 | *.pid 23 | *.seed 24 | *.pid.lock 25 | 26 | # Directory for instrumented libs generated by jscoverage/JSCover 27 | lib-cov 28 | 29 | # Coverage directory used by tools like istanbul 30 | coverage 31 | 32 | # nyc test coverage 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 36 | .grunt 37 | 38 | # Bower dependency directory (https://bower.io/) 39 | bower_components 40 | 41 | # node-waf configuration 42 | .lock-wscript 43 | 44 | # Compiled binary addons (http://nodejs.org/api/addons.html) 45 | build/Release 46 | 47 | # Dependency directories 48 | node_modules/ 49 | jspm_packages/ 50 | 51 | # Typescript v1 declaration files 52 | typings/ 53 | 54 | # Optional npm cache directory 55 | .npm 56 | 57 | # Optional eslint cache 58 | .eslintcache 59 | 60 | # Optional REPL history 61 | .node_repl_history 62 | 63 | # Output of 'npm pack' 64 | *.tgz 65 | 66 | # Yarn Integrity file 67 | .yarn-integrity 68 | 69 | # dotenv environment variables file 70 | .env 71 | 72 | 73 | 74 | ### https://raw.github.com/github/gitignore/4db4bb6e20ded299466202bfcb5b07f5cf3325cd/Global/macOS.gitignore 75 | 76 | # General 77 | *.DS_Store 78 | .AppleDouble 79 | .LSOverride 80 | 81 | # Icon must end with two \r 82 | Icon 83 | 84 | 85 | # Thumbnails 86 | ._* 87 | 88 | # Files that might appear in the root of a volume 89 | .DocumentRevisions-V100 90 | .fseventsd 91 | .Spotlight-V100 92 | .TemporaryItems 93 | .Trashes 94 | .VolumeIcon.icns 95 | .com.apple.timemachine.donotpresent 96 | 97 | # Directories potentially created on remote AFP share 98 | .AppleDB 99 | .AppleDesktop 100 | Network Trash Folder 101 | Temporary Items 102 | .apdisk 103 | 104 | 105 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Daiki Iizuka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SVG Screenshot 2 | -------------------------------------------------------------------------------- /chrome/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/chrome/.keep -------------------------------------------------------------------------------- /chrome/background.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /chrome/build/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/chrome/build/.keep -------------------------------------------------------------------------------- /chrome/css/insite.css: -------------------------------------------------------------------------------- 1 | .daiz-ss-cropper, .daiz-ss-cropper-main { 2 | border: 1px solid #777; 3 | cursor: move; 4 | background-color: #ddd; 5 | opacity: 0.4; 6 | cursor: pointer; 7 | box-sizing: border-box; 8 | z-index: 10000; 9 | } 10 | 11 | .daiz-ss-cropper { 12 | z-index: 100001; 13 | background-color: #FFD54F; 14 | border: 1px solid #FFC107; 15 | } 16 | 17 | .daiz-ss-cropper-text { 18 | z-index: 100001; 19 | background-color: #9575CD !important; 20 | border: 1px solid #673AB7 !important; 21 | } 22 | 23 | #daiz-ss-run, #daiz-ss-send { 24 | position: fixed; 25 | z-index: 10000; 26 | cursor: pointer; 27 | width: 30px; 28 | height: 30px; 29 | background-color: orange; 30 | border-radius: 4px; 31 | bottom: 12px; 32 | right: 12px; 33 | } 34 | 35 | #daiz-ss-send { 36 | background-color: #FFC107; 37 | bottom: 48px; 38 | } 39 | 40 | #export { 41 | color: #1E88E5; 42 | } 43 | 44 | .daiz-ss-iv-cover { 45 | background-color: #fff; 46 | z-index: 10000; 47 | box-sizing: content-box; 48 | box-shadow: 0 0px 2px 0 rgba(0,0,0,.14), 49 | 0 2px 1px -2px rgba(0,0,0,.2), 50 | 0 0px 5px 0 rgba(0,0,0,.12); 51 | /*box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),*/ 52 | /*0 3px 1px -2px rgba(0,0,0,.2),*/ 53 | /*0 1px 5px 0 rgba(0,0,0,.12);*/ 54 | position: absolute; 55 | overflow-x: hidden; 56 | overflow-y: hidden; 57 | background-color: rgba(0, 0, 0 ,0); 58 | border-radius: 1px; 59 | } 60 | 61 | .gyazo-com { 62 | z-index: 999; 63 | border: 1px solid #fff; 64 | } 65 | 66 | .daiz-ss-iv-svg { 67 | width: 100%; 68 | height: 100%; 69 | overflow-x: hidden; 70 | overflow-y: hidden; 71 | position: absolute; 72 | } 73 | 74 | .daiz-ss-iv-svg a { 75 | cursor: pointer; 76 | } 77 | 78 | .daiz-ss-iv-rbar { 79 | width: 7px; 80 | height: 100%; 81 | position: absolute; 82 | top: 0; 83 | right: 0; 84 | display: none; 85 | background-color: #fafafa; 86 | } 87 | 88 | .daiz-ss-iv-cover-foot { 89 | color: #888; 90 | position: absolute; 91 | left: 0px; 92 | bottom: 0px; 93 | padding-left: 6px; 94 | height: 20px; 95 | overflow: hidden; 96 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 97 | display: none; 98 | } 99 | 100 | .daiz-ss-iv-cover-foot a.footlink{ 101 | font-size: 11px; 102 | text-decoration: none; 103 | color: #888; 104 | } 105 | 106 | .daiz-ss-iv-cover-foot a.footlink:hover{ 107 | text-decoration: underline; 108 | color: #2962FF; 109 | } 110 | 111 | .daiz-ss-iv-cover-foot a.jump:hover{ 112 | text-decoration: underline; 113 | color: #2962FF; 114 | } 115 | 116 | .daiz-ss-iv-cover-foot .jump { 117 | margin-left: 6px; 118 | font-size: 11px; 119 | color: #888; 120 | } 121 | 122 | #daiz-ss-cropper-close, .daiz-ss-cropper-close, 123 | #daiz-ss-cropper-capture, .daiz-ss-cropper-capture, 124 | #daiz-ss-cropper-scrap-select, 125 | #daiz-ss-cropper-scrapbox { 126 | position: absolute; 127 | background-repeat: no-repeat; 128 | background-position: center center; 129 | z-index: 10001; 130 | color: #fff; 131 | padding: 2px; 132 | box-sizing: border-box; 133 | text-align: center; 134 | cursor: pointer; 135 | overflow: hidden; 136 | } 137 | 138 | #daiz-ss-cropper-scrap-select { 139 | color: #000; 140 | top: -10px; 141 | left: 95px; 142 | height: 20px; 143 | width: initial; 144 | border: initial; 145 | border-radius: initial; 146 | font-size: 11px; 147 | } 148 | 149 | .daiz-ss-cropper-main select { 150 | -webkit-appearance: menulist; 151 | background-image: none; 152 | } 153 | 154 | #daiz-ss-cropper-close, .daiz-ss-cropper-close { 155 | height: 20px; 156 | width: 20px; 157 | top: -10px; 158 | right: -10px; 159 | border-radius: 50%; 160 | background-color: #777; 161 | } 162 | 163 | #daiz-ss-cropper-capture, #daiz-ss-cropper-scrapbox, 164 | .daiz-ss-cropper-capture, .daiz-ss-cropper-scrapbox { 165 | height: 20px; 166 | left: -10px; 167 | top: -10px; 168 | font-size: 11px; 169 | line-height: 11px; 170 | background-color: green; 171 | border-radius: 4px; 172 | padding-left: 6px; 173 | padding-right: 6px; 174 | padding-top: 4px; 175 | padding-bottom: 4px; 176 | } 177 | 178 | #daiz-ss-cropper-scrapbox, .daiz-ss-cropper-scrapbox { 179 | left: 50px; 180 | height: 20px; 181 | } 182 | 183 | 184 | .card-area { 185 | position: fixed; 186 | background-color: #fff; 187 | top: 0; 188 | right: 0; 189 | width: 220px; 190 | height: 220px; 191 | padding: 28px; 192 | border-left: 1px solid #ccc; 193 | border-bottom: 1px solid #ccc; 194 | box-sizing: border-box; 195 | z-index: 10000; 196 | } 197 | 198 | .card-a { 199 | position: absolute; 200 | font-size: 13px; 201 | line-height: 18px; 202 | height: 36px; 203 | color: #4e505d; 204 | overflow: hidden; 205 | top: 36px; 206 | left: 36px; 207 | width: 139px; 208 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 209 | cursor: pointer; 210 | } 211 | 212 | .card-a a { 213 | color: #4e505d !important; 214 | height: 100%; 215 | width: 100%; 216 | position: absolute; 217 | overflow: hidden; 218 | text-decoration: none !important; 219 | } 220 | 221 | .card-a a:hover { 222 | text-decoration: none !important; 223 | } 224 | 225 | .card-thumbnail { 226 | position: absolute; 227 | background-color: #fff; 228 | background-position: center center; 229 | background-repeat: no-repeat; 230 | background-size: cover; 231 | box-sizing: border-box; 232 | width: 145px; 233 | height: 111px; 234 | top: 83px; 235 | left: 33px; 236 | } 237 | 238 | .card-close { 239 | position: absolute; 240 | top: 10px; 241 | right: 10px; 242 | background-color: rgb(119, 119, 119); 243 | border-radius: 50%; 244 | padding: 3px; 245 | cursor: pointer; 246 | } 247 | -------------------------------------------------------------------------------- /chrome/image/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/chrome/image/128x128.png -------------------------------------------------------------------------------- /chrome/image/icon-l.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/chrome/image/icon-l.png -------------------------------------------------------------------------------- /chrome/image/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/chrome/image/icon.png -------------------------------------------------------------------------------- /chrome/image/linkcard/scrapbox_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/chrome/image/linkcard/scrapbox_default.png -------------------------------------------------------------------------------- /chrome/image/x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/chrome/image/x.png -------------------------------------------------------------------------------- /chrome/lib/clipboard.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * clipboard.js v1.5.3 3 | * https://zenorocha.github.io/clipboard.js 4 | * 5 | * Licensed MIT © Zeno Rocha 6 | */ 7 | !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,r){function o(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(i)return i(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ar;r++)n[r].fn.apply(n[r].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var i=0,a=r.length;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;n=0)&&e(i,!n)}}),t("").outerWidth(1).jquery||t.each(["Width","Height"],function(e,i){function s(e,i,s,a){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),a&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],a=i.toLowerCase(),o={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?o["inner"+i].call(this):this.each(function(){t(this).css(a,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?o["outer"+i].call(this,e):this.each(function(){t(this).css(a,s(this,e,!0,n)+"px")})}}),t.fn.addBack||(t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t("").data("a-b","a").removeData("a-b").data("a-b")&&(t.fn.removeData=function(e){return function(i){return arguments.length?e.call(this,t.camelCase(i)):e.call(this)}}(t.fn.removeData)),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),t.fn.extend({focus:function(e){return function(i,s){return"number"==typeof i?this.each(function(){var e=this;setTimeout(function(){t(e).focus(),s&&s.call(e)},i)}):e.apply(this,arguments)}}(t.fn.focus),disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.bind(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.unbind(".ui-disableSelection")},zIndex:function(e){if(void 0!==e)return this.css("zIndex",e);if(this.length)for(var i,s,n=t(this[0]);n.length&&n[0]!==document;){if(i=n.css("position"),("absolute"===i||"relative"===i||"fixed"===i)&&(s=parseInt(n.css("zIndex"),10),!isNaN(s)&&0!==s))return s;n=n.parent()}return 0}}),t.ui.plugin={add:function(e,i,s){var n,a=t.ui[e].prototype;for(n in s)a.plugins[n]=a.plugins[n]||[],a.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,a=t.plugins[e];if(a&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;a.length>n;n++)t.options[a[n][0]]&&a[n][1].apply(t.element,i)}};var s=0,n=Array.prototype.slice;t.cleanData=function(e){return function(i){var s,n,a;for(a=0;null!=(n=i[a]);a++)try{s=t._data(n,"events"),s&&s.remove&&t(n).triggerHandler("remove")}catch(o){}e(i)}}(t.cleanData),t.widget=function(e,i,s){var n,a,o,r,h={},l=e.split(".")[0];return e=e.split(".")[1],n=l+"-"+e,s||(s=i,i=t.Widget),t.expr[":"][n.toLowerCase()]=function(e){return!!t.data(e,n)},t[l]=t[l]||{},a=t[l][e],o=t[l][e]=function(t,e){return this._createWidget?(arguments.length&&this._createWidget(t,e),void 0):new o(t,e)},t.extend(o,a,{version:s.version,_proto:t.extend({},s),_childConstructors:[]}),r=new i,r.options=t.widget.extend({},r.options),t.each(s,function(e,s){return t.isFunction(s)?(h[e]=function(){var t=function(){return i.prototype[e].apply(this,arguments)},n=function(t){return i.prototype[e].apply(this,t)};return function(){var e,i=this._super,a=this._superApply;return this._super=t,this._superApply=n,e=s.apply(this,arguments),this._super=i,this._superApply=a,e}}(),void 0):(h[e]=s,void 0)}),o.prototype=t.widget.extend(r,{widgetEventPrefix:a?r.widgetEventPrefix||e:e},h,{constructor:o,namespace:l,widgetName:e,widgetFullName:n}),a?(t.each(a._childConstructors,function(e,i){var s=i.prototype;t.widget(s.namespace+"."+s.widgetName,o,i._proto)}),delete a._childConstructors):i._childConstructors.push(o),t.widget.bridge(e,o),o},t.widget.extend=function(e){for(var i,s,a=n.call(arguments,1),o=0,r=a.length;r>o;o++)for(i in a[o])s=a[o][i],a[o].hasOwnProperty(i)&&void 0!==s&&(e[i]=t.isPlainObject(s)?t.isPlainObject(e[i])?t.widget.extend({},e[i],s):t.widget.extend({},s):s);return e},t.widget.bridge=function(e,i){var s=i.prototype.widgetFullName||e;t.fn[e]=function(a){var o="string"==typeof a,r=n.call(arguments,1),h=this;return o?this.each(function(){var i,n=t.data(this,s);return"instance"===a?(h=n,!1):n?t.isFunction(n[a])&&"_"!==a.charAt(0)?(i=n[a].apply(n,r),i!==n&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+a+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+a+"'")}):(r.length&&(a=t.widget.extend.apply(null,[a].concat(r))),this.each(function(){var e=t.data(this,s);e?(e.option(a||{}),e._init&&e._init()):t.data(this,s,new i(a,this))})),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{disabled:!1,create:null},_createWidget:function(e,i){i=t(i||this.defaultElement||this)[0],this.element=t(i),this.uuid=s++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),i!==this&&(t.data(i,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===i&&this.destroy()}}),this.document=t(i.style?i.ownerDocument:i.document||i),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:t.noop,_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetFullName).removeData(t.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,a,o=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(o={},s=e.split("."),e=s.shift(),s.length){for(n=o[e]=t.widget.extend({},this.options[e]),a=0;s.length-1>a;a++)n[s[a]]=n[s[a]]||{},n=n[s[a]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];o[e]=i}return this._setOptions(o),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return this.options[t]=e,"disabled"===t&&(this.widget().toggleClass(this.widgetFullName+"-disabled",!!e),e&&(this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus"))),this},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_on:function(e,i,s){var n,a=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,o){function r(){return e||a.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof o?a[o]:o).apply(a,arguments):void 0}"string"!=typeof o&&(r.guid=o.guid=o.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+a.eventNamespace,u=h[2];u?n.delegate(u,l,r):i.bind(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.unbind(i).undelegate(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){t(e.currentTarget).addClass("ui-state-hover")},mouseleave:function(e){t(e.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){t(e.currentTarget).addClass("ui-state-focus")},focusout:function(e){t(e.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(e,i,s){var n,a,o=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],a=i.originalEvent)for(n in a)n in i||(i[n]=a[n]);return this.element.trigger(i,s),!(t.isFunction(o)&&o.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,a){"string"==typeof n&&(n={effect:n});var o,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),o=!t.isEmptyObject(n),n.complete=a,n.delay&&s.delay(n.delay),o&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,a):s.queue(function(i){t(this)[e](),a&&a.call(s[0]),i()})}}),t.widget;var a=!1;t(document).mouseup(function(){a=!1}),t.widget("ui.mouse",{version:"1.11.4",options:{cancel:"input,textarea,button,select,option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.bind("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).bind("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.unbind("."+this.widgetName),this._mouseMoveDelegate&&this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!a){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,n="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!n&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),a=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){return this.document.unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),a=!1,!1},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),function(){function e(t,e,i){return[parseFloat(t[0])*(p.test(t[0])?e/100:1),parseFloat(t[1])*(p.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}t.ui=t.ui||{};var n,a,o=Math.max,r=Math.abs,h=Math.round,l=/left|center|right/,u=/top|center|bottom/,c=/[\+\-]\d+(\.[\d]+)?%?/,d=/^\w+/,p=/%$/,f=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),a=s.children()[0];return t("body").append(s),e=a.offsetWidth,s.css("overflow","scroll"),i=a.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>a?"top":s>0?"bottom":"middle"};c>m&&m>r(e+i)&&(h.horizontal="center"),d>g&&g>r(s+a)&&(h.vertical="middle"),h.important=o(r(e),r(i))>o(r(s),r(a))?"horizontal":"vertical",n.using.call(this,t,h)}),u.offset(t.extend(M,{using:l}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,a=n.offset.left+n.scrollLeft,o=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,u=l-h,c=l+e.collisionWidth-o-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>u?(i=t.left+d+p+f+e.collisionWidth-o-a,(0>i||r(u)>i)&&(t.left+=d+p+f)):c>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||c>r(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,a=n.offset.top+n.scrollTop,o=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,u=l-h,c=l+e.collisionHeight-o-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>u?(s=t.top+p+f+m+e.collisionHeight-o-a,(0>s||r(u)>s)&&(t.top+=p+f+m)):c>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,(i>0||c>r(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}},function(){var e,i,s,n,o,r=document.getElementsByTagName("body")[0],h=document.createElement("div");e=document.createElement(r?"div":"body"),s={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},r&&t.extend(s,{position:"absolute",left:"-1000px",top:"-1000px"});for(o in s)e.style[o]=s[o];e.appendChild(h),i=r||document.documentElement,i.insertBefore(e,i.firstChild),h.style.cssText="position: absolute; left: 10.7432222px;",n=t(h).offset().left,a=n>10&&11>n,e.innerHTML="",i.removeChild(e)}()}(),t.ui.position,t.widget("ui.draggable",t.ui.mouse,{version:"1.11.4",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1,drag:null,start:null,stop:null},_create:function(){"original"===this.options.helper&&this._setPositionRelative(),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._setHandleClassName(),this._mouseInit()},_setOption:function(t,e){this._super(t,e),"handle"===t&&(this._removeHandleClassName(),this._setHandleClassName())},_destroy:function(){return(this.helper||this.element).is(".ui-draggable-dragging")?(this.destroyOnClear=!0,void 0):(this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._removeHandleClassName(),this._mouseDestroy(),void 0)},_mouseCapture:function(e){var i=this.options;return this._blurActiveElement(e),this.helper||i.disabled||t(e.target).closest(".ui-resizable-handle").length>0?!1:(this.handle=this._getHandle(e),this.handle?(this._blockFrames(i.iframeFix===!0?"iframe":i.iframeFix),!0):!1)},_blockFrames:function(e){this.iframeBlocks=this.document.find(e).map(function(){var e=t(this);return t("
").css("position","absolute").appendTo(e.parent()).outerWidth(e.outerWidth()).outerHeight(e.outerHeight()).offset(e.offset())[0]})},_unblockFrames:function(){this.iframeBlocks&&(this.iframeBlocks.remove(),delete this.iframeBlocks)},_blurActiveElement:function(e){var i=this.document[0];if(this.handleElement.is(e.target))try{i.activeElement&&"body"!==i.activeElement.nodeName.toLowerCase()&&t(i.activeElement).blur()}catch(s){}},_mouseStart:function(e){var i=this.options;return this.helper=this._createHelper(e),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),t.ui.ddmanager&&(t.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(!0),this.offsetParent=this.helper.offsetParent(),this.hasFixedAncestor=this.helper.parents().filter(function(){return"fixed"===t(this).css("position")}).length>0,this.positionAbs=this.element.offset(),this._refreshOffsets(e),this.originalPosition=this.position=this._generatePosition(e,!1),this.originalPageX=e.pageX,this.originalPageY=e.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this._setContainment(),this._trigger("start",e)===!1?(this._clear(),!1):(this._cacheHelperProportions(),t.ui.ddmanager&&!i.dropBehaviour&&t.ui.ddmanager.prepareOffsets(this,e),this._normalizeRightBottom(),this._mouseDrag(e,!0),t.ui.ddmanager&&t.ui.ddmanager.dragStart(this,e),!0)},_refreshOffsets:function(t){this.offset={top:this.positionAbs.top-this.margins.top,left:this.positionAbs.left-this.margins.left,scroll:!1,parent:this._getParentOffset(),relative:this._getRelativeOffset()},this.offset.click={left:t.pageX-this.offset.left,top:t.pageY-this.offset.top}},_mouseDrag:function(e,i){if(this.hasFixedAncestor&&(this.offset.parent=this._getParentOffset()),this.position=this._generatePosition(e,!0),this.positionAbs=this._convertPositionTo("absolute"),!i){var s=this._uiHash();if(this._trigger("drag",e,s)===!1)return this._mouseUp({}),!1;this.position=s.position}return this.helper[0].style.left=this.position.left+"px",this.helper[0].style.top=this.position.top+"px",t.ui.ddmanager&&t.ui.ddmanager.drag(this,e),!1},_mouseStop:function(e){var i=this,s=!1;return t.ui.ddmanager&&!this.options.dropBehaviour&&(s=t.ui.ddmanager.drop(this,e)),this.dropped&&(s=this.dropped,this.dropped=!1),"invalid"===this.options.revert&&!s||"valid"===this.options.revert&&s||this.options.revert===!0||t.isFunction(this.options.revert)&&this.options.revert.call(this.element,s)?t(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){i._trigger("stop",e)!==!1&&i._clear()}):this._trigger("stop",e)!==!1&&this._clear(),!1},_mouseUp:function(e){return this._unblockFrames(),t.ui.ddmanager&&t.ui.ddmanager.dragStop(this,e),this.handleElement.is(e.target)&&this.element.focus(),t.ui.mouse.prototype._mouseUp.call(this,e)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(e){return this.options.handle?!!t(e.target).closest(this.element.find(this.options.handle)).length:!0},_setHandleClassName:function(){this.handleElement=this.options.handle?this.element.find(this.options.handle):this.element,this.handleElement.addClass("ui-draggable-handle")},_removeHandleClassName:function(){this.handleElement.removeClass("ui-draggable-handle")},_createHelper:function(e){var i=this.options,s=t.isFunction(i.helper),n=s?t(i.helper.apply(this.element[0],[e])):"clone"===i.helper?this.element.clone().removeAttr("id"):this.element;return n.parents("body").length||n.appendTo("parent"===i.appendTo?this.element[0].parentNode:i.appendTo),s&&n[0]===this.element[0]&&this._setPositionRelative(),n[0]===this.element[0]||/(fixed|absolute)/.test(n.css("position"))||n.css("position","absolute"),n},_setPositionRelative:function(){/^(?:r|a|f)/.test(this.element.css("position"))||(this.element[0].style.position="relative")},_adjustOffsetFromHelper:function(e){"string"==typeof e&&(e=e.split(" ")),t.isArray(e)&&(e={left:+e[0],top:+e[1]||0}),"left"in e&&(this.offset.click.left=e.left+this.margins.left),"right"in e&&(this.offset.click.left=this.helperProportions.width-e.right+this.margins.left),"top"in e&&(this.offset.click.top=e.top+this.margins.top),"bottom"in e&&(this.offset.click.top=this.helperProportions.height-e.bottom+this.margins.top)},_isRootNode:function(t){return/(html|body)/i.test(t.tagName)||t===this.document[0]},_getParentOffset:function(){var e=this.offsetParent.offset(),i=this.document[0];return"absolute"===this.cssPosition&&this.scrollParent[0]!==i&&t.contains(this.scrollParent[0],this.offsetParent[0])&&(e.left+=this.scrollParent.scrollLeft(),e.top+=this.scrollParent.scrollTop()),this._isRootNode(this.offsetParent[0])&&(e={top:0,left:0}),{top:e.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:e.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if("relative"!==this.cssPosition)return{top:0,left:0};var t=this.element.position(),e=this._isRootNode(this.scrollParent[0]);return{top:t.top-(parseInt(this.helper.css("top"),10)||0)+(e?0:this.scrollParent.scrollTop()),left:t.left-(parseInt(this.helper.css("left"),10)||0)+(e?0:this.scrollParent.scrollLeft())}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e,i,s,n=this.options,a=this.document[0];return this.relativeContainer=null,n.containment?"window"===n.containment?(this.containment=[t(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,t(window).scrollLeft()+t(window).width()-this.helperProportions.width-this.margins.left,t(window).scrollTop()+(t(window).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):"document"===n.containment?(this.containment=[0,0,t(a).width()-this.helperProportions.width-this.margins.left,(t(a).height()||a.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top],void 0):n.containment.constructor===Array?(this.containment=n.containment,void 0):("parent"===n.containment&&(n.containment=this.helper[0].parentNode),i=t(n.containment),s=i[0],s&&(e=/(scroll|auto)/.test(i.css("overflow")),this.containment=[(parseInt(i.css("borderLeftWidth"),10)||0)+(parseInt(i.css("paddingLeft"),10)||0),(parseInt(i.css("borderTopWidth"),10)||0)+(parseInt(i.css("paddingTop"),10)||0),(e?Math.max(s.scrollWidth,s.offsetWidth):s.offsetWidth)-(parseInt(i.css("borderRightWidth"),10)||0)-(parseInt(i.css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(e?Math.max(s.scrollHeight,s.offsetHeight):s.offsetHeight)-(parseInt(i.css("borderBottomWidth"),10)||0)-(parseInt(i.css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relativeContainer=i),void 0):(this.containment=null,void 0)},_convertPositionTo:function(t,e){e||(e=this.position);var i="absolute"===t?1:-1,s=this._isRootNode(this.scrollParent[0]);return{top:e.top+this.offset.relative.top*i+this.offset.parent.top*i-("fixed"===this.cssPosition?-this.offset.scroll.top:s?0:this.offset.scroll.top)*i,left:e.left+this.offset.relative.left*i+this.offset.parent.left*i-("fixed"===this.cssPosition?-this.offset.scroll.left:s?0:this.offset.scroll.left)*i}},_generatePosition:function(t,e){var i,s,n,a,o=this.options,r=this._isRootNode(this.scrollParent[0]),h=t.pageX,l=t.pageY;return r&&this.offset.scroll||(this.offset.scroll={top:this.scrollParent.scrollTop(),left:this.scrollParent.scrollLeft()}),e&&(this.containment&&(this.relativeContainer?(s=this.relativeContainer.offset(),i=[this.containment[0]+s.left,this.containment[1]+s.top,this.containment[2]+s.left,this.containment[3]+s.top]):i=this.containment,t.pageX-this.offset.click.lefti[2]&&(h=i[2]+this.offset.click.left),t.pageY-this.offset.click.top>i[3]&&(l=i[3]+this.offset.click.top)),o.grid&&(n=o.grid[1]?this.originalPageY+Math.round((l-this.originalPageY)/o.grid[1])*o.grid[1]:this.originalPageY,l=i?n-this.offset.click.top>=i[1]||n-this.offset.click.top>i[3]?n:n-this.offset.click.top>=i[1]?n-o.grid[1]:n+o.grid[1]:n,a=o.grid[0]?this.originalPageX+Math.round((h-this.originalPageX)/o.grid[0])*o.grid[0]:this.originalPageX,h=i?a-this.offset.click.left>=i[0]||a-this.offset.click.left>i[2]?a:a-this.offset.click.left>=i[0]?a-o.grid[0]:a+o.grid[0]:a),"y"===o.axis&&(h=this.originalPageX),"x"===o.axis&&(l=this.originalPageY)),{top:l-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.offset.scroll.top:r?0:this.offset.scroll.top),left:h-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.offset.scroll.left:r?0:this.offset.scroll.left)}},_clear:function(){this.helper.removeClass("ui-draggable-dragging"),this.helper[0]===this.element[0]||this.cancelHelperRemoval||this.helper.remove(),this.helper=null,this.cancelHelperRemoval=!1,this.destroyOnClear&&this.destroy()},_normalizeRightBottom:function(){"y"!==this.options.axis&&"auto"!==this.helper.css("right")&&(this.helper.width(this.helper.width()),this.helper.css("right","auto")),"x"!==this.options.axis&&"auto"!==this.helper.css("bottom")&&(this.helper.height(this.helper.height()),this.helper.css("bottom","auto"))},_trigger:function(e,i,s){return s=s||this._uiHash(),t.ui.plugin.call(this,e,[i,s,this],!0),/^(drag|start|stop)/.test(e)&&(this.positionAbs=this._convertPositionTo("absolute"),s.offset=this.positionAbs),t.Widget.prototype._trigger.call(this,e,i,s)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}}),t.ui.plugin.add("draggable","connectToSortable",{start:function(e,i,s){var n=t.extend({},i,{item:s.element});s.sortables=[],t(s.options.connectToSortable).each(function(){var i=t(this).sortable("instance");i&&!i.options.disabled&&(s.sortables.push(i),i.refreshPositions(),i._trigger("activate",e,n))})},stop:function(e,i,s){var n=t.extend({},i,{item:s.element});s.cancelHelperRemoval=!1,t.each(s.sortables,function(){var t=this;t.isOver?(t.isOver=0,s.cancelHelperRemoval=!0,t.cancelHelperRemoval=!1,t._storedCSS={position:t.placeholder.css("position"),top:t.placeholder.css("top"),left:t.placeholder.css("left")},t._mouseStop(e),t.options.helper=t.options._helper):(t.cancelHelperRemoval=!0,t._trigger("deactivate",e,n))})},drag:function(e,i,s){t.each(s.sortables,function(){var n=!1,a=this;a.positionAbs=s.positionAbs,a.helperProportions=s.helperProportions,a.offset.click=s.offset.click,a._intersectsWith(a.containerCache)&&(n=!0,t.each(s.sortables,function(){return this.positionAbs=s.positionAbs,this.helperProportions=s.helperProportions,this.offset.click=s.offset.click,this!==a&&this._intersectsWith(this.containerCache)&&t.contains(a.element[0],this.element[0])&&(n=!1),n 7 | })),n?(a.isOver||(a.isOver=1,s._parent=i.helper.parent(),a.currentItem=i.helper.appendTo(a.element).data("ui-sortable-item",!0),a.options._helper=a.options.helper,a.options.helper=function(){return i.helper[0]},e.target=a.currentItem[0],a._mouseCapture(e,!0),a._mouseStart(e,!0,!0),a.offset.click.top=s.offset.click.top,a.offset.click.left=s.offset.click.left,a.offset.parent.left-=s.offset.parent.left-a.offset.parent.left,a.offset.parent.top-=s.offset.parent.top-a.offset.parent.top,s._trigger("toSortable",e),s.dropped=a.element,t.each(s.sortables,function(){this.refreshPositions()}),s.currentItem=s.element,a.fromOutside=s),a.currentItem&&(a._mouseDrag(e),i.position=a.position)):a.isOver&&(a.isOver=0,a.cancelHelperRemoval=!0,a.options._revert=a.options.revert,a.options.revert=!1,a._trigger("out",e,a._uiHash(a)),a._mouseStop(e,!0),a.options.revert=a.options._revert,a.options.helper=a.options._helper,a.placeholder&&a.placeholder.remove(),i.helper.appendTo(s._parent),s._refreshOffsets(e),i.position=s._generatePosition(e,!0),s._trigger("fromSortable",e),s.dropped=!1,t.each(s.sortables,function(){this.refreshPositions()}))})}}),t.ui.plugin.add("draggable","cursor",{start:function(e,i,s){var n=t("body"),a=s.options;n.css("cursor")&&(a._cursor=n.css("cursor")),n.css("cursor",a.cursor)},stop:function(e,i,s){var n=s.options;n._cursor&&t("body").css("cursor",n._cursor)}}),t.ui.plugin.add("draggable","opacity",{start:function(e,i,s){var n=t(i.helper),a=s.options;n.css("opacity")&&(a._opacity=n.css("opacity")),n.css("opacity",a.opacity)},stop:function(e,i,s){var n=s.options;n._opacity&&t(i.helper).css("opacity",n._opacity)}}),t.ui.plugin.add("draggable","scroll",{start:function(t,e,i){i.scrollParentNotHidden||(i.scrollParentNotHidden=i.helper.scrollParent(!1)),i.scrollParentNotHidden[0]!==i.document[0]&&"HTML"!==i.scrollParentNotHidden[0].tagName&&(i.overflowOffset=i.scrollParentNotHidden.offset())},drag:function(e,i,s){var n=s.options,a=!1,o=s.scrollParentNotHidden[0],r=s.document[0];o!==r&&"HTML"!==o.tagName?(n.axis&&"x"===n.axis||(s.overflowOffset.top+o.offsetHeight-e.pageY=0;d--)h=s.snapElements[d].left-s.margins.left,l=h+s.snapElements[d].width,u=s.snapElements[d].top-s.margins.top,c=u+s.snapElements[d].height,h-m>v||g>l+m||u-m>b||_>c+m||!t.contains(s.snapElements[d].item.ownerDocument,s.snapElements[d].item)?(s.snapElements[d].snapping&&s.options.snap.release&&s.options.snap.release.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=!1):("inner"!==f.snapMode&&(n=m>=Math.abs(u-b),a=m>=Math.abs(c-_),o=m>=Math.abs(h-v),r=m>=Math.abs(l-g),n&&(i.position.top=s._convertPositionTo("relative",{top:u-s.helperProportions.height,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:c,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h-s.helperProportions.width}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l}).left)),p=n||a||o||r,"outer"!==f.snapMode&&(n=m>=Math.abs(u-_),a=m>=Math.abs(c-b),o=m>=Math.abs(h-g),r=m>=Math.abs(l-v),n&&(i.position.top=s._convertPositionTo("relative",{top:u,left:0}).top),a&&(i.position.top=s._convertPositionTo("relative",{top:c-s.helperProportions.height,left:0}).top),o&&(i.position.left=s._convertPositionTo("relative",{top:0,left:h}).left),r&&(i.position.left=s._convertPositionTo("relative",{top:0,left:l-s.helperProportions.width}).left)),!s.snapElements[d].snapping&&(n||a||o||r||p)&&s.options.snap.snap&&s.options.snap.snap.call(s.element,e,t.extend(s._uiHash(),{snapItem:s.snapElements[d].item})),s.snapElements[d].snapping=n||a||o||r||p)}}),t.ui.plugin.add("draggable","stack",{start:function(e,i,s){var n,a=s.options,o=t.makeArray(t(a.stack)).sort(function(e,i){return(parseInt(t(e).css("zIndex"),10)||0)-(parseInt(t(i).css("zIndex"),10)||0)});o.length&&(n=parseInt(t(o[0]).css("zIndex"),10)||0,t(o).each(function(e){t(this).css("zIndex",n+e)}),this.css("zIndex",n+o.length))}}),t.ui.plugin.add("draggable","zIndex",{start:function(e,i,s){var n=t(i.helper),a=s.options;n.css("zIndex")&&(a._zIndex=n.css("zIndex")),n.css("zIndex",a.zIndex)},stop:function(e,i,s){var n=s.options;n._zIndex&&t(i.helper).css("zIndex",n._zIndex)}}),t.ui.draggable,t.widget("ui.resizable",t.ui.mouse,{version:"1.11.4",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseInt(t,10)||0},_isNumber:function(t){return!isNaN(parseInt(t,10))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i,s,n,a,o=this,r=this.options;if(this.element.addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!r.aspectRatio,aspectRatio:r.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:r.helper||r.ghost||r.animate?r.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=r.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),e=this.handles.split(","),this.handles={},i=0;e.length>i;i++)s=t.trim(e[i]),a="ui-resizable-"+s,n=t("
"),n.css({zIndex:r.zIndex}),"se"===s&&n.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(n);this._renderAxis=function(e){var i,s,n,a;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:o._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),a=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,a),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.mouseover(function(){o.resizing||(this.className&&(n=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),o.axis=n&&n[1]?n[1]:"se")}),r.autoHide&&(this._handles.hide(),t(this.element).addClass("ui-resizable-autohide").mouseenter(function(){r.disabled||(t(this).removeClass("ui-resizable-autohide"),o._handles.show())}).mouseleave(function(){r.disabled||o.resizing||(t(this).addClass("ui-resizable-autohide"),o._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,a=this.options,o=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),a.containment&&(i+=t(a.containment).scrollLeft()||0,s+=t(a.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:o.width(),height:o.height()},this.originalSize=this._helper?{width:o.outerWidth(),height:o.outerHeight()}:{width:o.width(),height:o.height()},this.sizeDiff={width:o.outerWidth()-o.width(),height:o.outerHeight()-o.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof a.aspectRatio?a.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),o.addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,a=this.axis,o=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[a];return this._updatePrevProperties(),h?(i=h.apply(this,[e,o,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,a,o,r,h,l=this.options,u=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:u.sizeDiff.height,a=s?0:u.sizeDiff.width,o={width:u.helper.width()-a,height:u.helper.height()-n},r=parseInt(u.element.css("left"),10)+(u.position.left-u.originalPosition.left)||null,h=parseInt(u.element.css("top"),10)+(u.position.top-u.originalPosition.top)||null,l.animate||this.element.css(t.extend(o,{top:h,left:r})),u.helper.height(u.size.height),u.helper.width(u.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,a,o=this.options;a={minWidth:this._isNumber(o.minWidth)?o.minWidth:0,maxWidth:this._isNumber(o.maxWidth)?o.maxWidth:1/0,minHeight:this._isNumber(o.minHeight)?o.minHeight:0,maxHeight:this._isNumber(o.maxHeight)?o.maxHeight:1/0},(this._aspectRatio||t)&&(e=a.minHeight*this.aspectRatio,s=a.minWidth/this.aspectRatio,i=a.maxHeight*this.aspectRatio,n=a.maxWidth/this.aspectRatio,e>a.minWidth&&(a.minWidth=e),s>a.minHeight&&(a.minHeight=s),a.maxWidth>i&&(a.maxWidth=i),a.maxHeight>n&&(a.maxHeight=n)),this._vBoundaries=a},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,o=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,l=/sw|nw|w/.test(i),u=/nw|ne|n/.test(i);return a&&(t.width=e.minWidth),o&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),a&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),o&&u&&(t.top=h-e.minHeight),n&&u&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseInt(s[e],10)||0,i[e]+=parseInt(n[e],10)||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
"),this.helper.addClass(this._helper).css({width:this.element.outerWidth()-1,height:this.element.outerHeight()-1,position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,a=n.length&&/textarea/i.test(n[0].nodeName),o=a&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=a?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-o},l=parseInt(i.element.css("left"),10)+(i.position.left-i.originalPosition.left)||null,u=parseInt(i.element.css("top"),10)+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,u&&l?{top:u,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseInt(i.element.css("width"),10),height:parseInt(i.element.css("height"),10),top:parseInt(i.element.css("top"),10),left:parseInt(i.element.css("left"),10)};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,a,o,r,h=t(this).resizable("instance"),l=h.options,u=h.element,c=l.containment,d=c instanceof t?c.get(0):/parent/.test(c)?u.parent().get(0):c;d&&(h.containerElement=t(d),/document/.test(c)||c===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,a=h.containerSize.width,o=h._hasScroll(d,"left")?d.scrollWidth:a,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:o,height:r}))},resize:function(e){var i,s,n,a,o=t(this).resizable("instance"),r=o.options,h=o.containerOffset,l=o.position,u=o._aspectRatio||e.shiftKey,c={top:0,left:0},d=o.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(c=h),l.left<(o._helper?h.left:0)&&(o.size.width=o.size.width+(o._helper?o.position.left-h.left:o.position.left-c.left),u&&(o.size.height=o.size.width/o.aspectRatio,p=!1),o.position.left=r.helper?h.left:0),l.top<(o._helper?h.top:0)&&(o.size.height=o.size.height+(o._helper?o.position.top-h.top:o.position.top),u&&(o.size.width=o.size.height*o.aspectRatio,p=!1),o.position.top=o._helper?h.top:0),n=o.containerElement.get(0)===o.element.parent().get(0),a=/relative|absolute/.test(o.containerElement.css("position")),n&&a?(o.offset.left=o.parentData.left+o.position.left,o.offset.top=o.parentData.top+o.position.top):(o.offset.left=o.element.offset().left,o.offset.top=o.element.offset().top),i=Math.abs(o.sizeDiff.width+(o._helper?o.offset.left-c.left:o.offset.left-h.left)),s=Math.abs(o.sizeDiff.height+(o._helper?o.offset.top-c.top:o.offset.top-h.top)),i+o.size.width>=o.parentData.width&&(o.size.width=o.parentData.width-i,u&&(o.size.height=o.size.width/o.aspectRatio,p=!1)),s+o.size.height>=o.parentData.height&&(o.size.height=o.parentData.height-s,u&&(o.size.width=o.size.height*o.aspectRatio,p=!1)),p||(o.position.left=o.prevPosition.left,o.position.top=o.prevPosition.top,o.size.width=o.prevSize.width,o.size.height=o.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,a=e.containerElement,o=t(e.helper),r=o.offset(),h=o.outerWidth()-e.sizeDiff.width,l=o.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(a.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(a.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseInt(e.width(),10),height:parseInt(e.height(),10),left:parseInt(e.css("left"),10),top:parseInt(e.css("top"),10)})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,a=s.originalSize,o=s.originalPosition,r={height:s.size.height-a.height||0,width:s.size.width-a.width||0,top:s.position.top-o.top||0,left:s.position.left-o.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},a=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(a,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.options,s=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass("string"==typeof i.ghost?i.ghost:""),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,a=i.originalSize,o=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,u=h[1]||1,c=Math.round((n.width-a.width)/l)*l,d=Math.round((n.height-a.height)/u)*u,p=a.width+c,f=a.height+d,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,v=s.minWidth&&s.minWidth>p,_=s.minHeight&&s.minHeight>f;s.grid=h,v&&(p+=l),_&&(f+=u),m&&(p-=l),g&&(f-=u),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=o.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=o.left-c):((0>=f-u||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-u>0?(i.size.height=f,i.position.top=o.top-d):(f=u-e.height,i.size.height=f,i.position.top=o.top+a.height-f),p-l>0?(i.size.width=p,i.position.left=o.left-c):(p=l-e.width,i.size.width=p,i.position.left=o.left+a.width-p))}}),t.ui.resizable}); -------------------------------------------------------------------------------- /chrome/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "background": { 3 | "page": "background.html" 4 | }, 5 | "options_ui": { 6 | "page": "options.html", 7 | "open_in_tab": false 8 | }, 9 | "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'", 10 | "description": "SVG Screenshot", 11 | "icons": { 12 | "128": "image/icon.png", 13 | "48" : "image/icon.png", 14 | "16" : "image/icon.png" 15 | }, 16 | "browser_action": { 17 | "default_icon": { 18 | "19": "image/icon-l.png", 19 | "38": "image/icon-l.png" 20 | }, 21 | "default_title": "SVG Screenshot", 22 | "default_popup": "popup.html" 23 | }, 24 | "manifest_version": 2, 25 | "name": "SVG Screenshot", 26 | "content_scripts": [{ 27 | "matches": [""], 28 | "css": [ 29 | "lib/jquery-ui.min.css", 30 | "css/insite.css" 31 | ], 32 | "js": [ 33 | "lib/jquery.js", 34 | "lib/jquery-ui.min.js", 35 | "build/bundle.js", 36 | "build/common.js", 37 | "build/inline_viewer.js", 38 | "build/content_script.js" 39 | ], 40 | "run_at": "document_end" 41 | }], 42 | 43 | "web_accessible_resources": [ 44 | "image/x.png", 45 | "image/linkcard/*" 46 | ], 47 | 48 | "permissions": [ 49 | "contextMenus", 50 | "pageCapture", 51 | "tabs", 52 | "activeTab", 53 | "cookies", 54 | "" 55 | ], 56 | "version": "0.7.7" 57 | } 58 | -------------------------------------------------------------------------------- /chrome/options.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Settings - SVG ScreenShot 6 | 7 | 20 | 21 | 22 |
23 | The following feature can be used only when logged in to 24 | Gyazo. 25 |
26 |

27 | 28 | Gyazoにもアップロードする 29 | 30 |
31 |

33 | 34 |
35 |
36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /chrome/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DynamicGazo 6 | 33 | 39 | 40 | 41 | 42 |

SVG Screenshot

43 | 44 |
45 | 46 | 範囲選択して撮影できます。 47 |
48 | 49 | 64 | 65 |
66 |

SVG Screenshot

67 |
68 | Googleアカウントでログイン |  69 | コレクションページを開く 70 |
71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /client/background.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | let META = {} 3 | 4 | const uploadToGyazo = async ({svgScreenshotImageId, hashTag, base64Img, devicePixelRatio}) => { 5 | const {baseUri, title} = META 6 | await window.dynamicGazo.uploadToGyazo({ 7 | title, 8 | referer: baseUri, 9 | image: base64Img, 10 | scale: devicePixelRatio, 11 | svgScreenshotImageId, 12 | hashTag 13 | }) 14 | } 15 | 16 | const uploadToSVGScreenshot = async ({devicePixelRatio}) => { 17 | const {baseUri, title, base64Img} = META 18 | const {useGyazo, gyazoHashtag} = readOptions() 19 | 20 | // SVGタグを生成する 21 | const svg = createSVGTag(META) 22 | const imageDataURI = dynamicGazo.addPhysChunk(base64Img, devicePixelRatio) 23 | const res = await dynamicGazo.uploadToDynamicGazo({ 24 | svg, 25 | title, 26 | referer: baseUri, 27 | base64Img: imageDataURI, 28 | devicePixelRatio 29 | }) 30 | if (res.status === 200 && res.data.x_key) { 31 | updateLocalStorage({ 32 | item_url: `${window.dynamicGazo.appOrigin}/x/${res.data.x_key}`, 33 | item_img: `${window.dynamicGazo.appOrigin}/c/x/${res.data.x_key}.png`, 34 | message: 'y' 35 | }) 36 | 37 | if (useGyazo === 'yes') { 38 | setBadgeUploadingToGyazo() 39 | await uploadToGyazo({ 40 | svgScreenshotImageId: res.data.x_key, 41 | hashTag: gyazoHashtag || '', 42 | base64Img: imageDataURI, 43 | devicePixelRatio 44 | }) 45 | } 46 | clearBadge() 47 | } else { 48 | // XXX: 適切なstatus codeが返ってきていない! 49 | handleError(res.data) 50 | } 51 | return res 52 | } 53 | 54 | 55 | const updateLocalStorage = ({item_url, item_img, message} = {item_url: '', item_img: ''}) => { 56 | localStorage.item_url = item_url 57 | localStorage.item_img = item_img 58 | localStorage.is_error = message 59 | } 60 | 61 | const handleError = ({ status }) => { 62 | chrome.browserAction.setBadgeBackgroundColor({ color: 'red' }) 63 | chrome.browserAction.setBadgeText({ text: '😇' }) 64 | switch (status) { 65 | case 'exceed-screenshots-upper-limit': { 66 | updateLocalStorage({ 67 | message: 'ファイルの上限数に達しています。' 68 | }) 69 | break 70 | } 71 | case 'no-login': { 72 | updateLocalStorage({ 73 | message: 'ウェブアプリにログインしていません。' 74 | }) 75 | break 76 | } 77 | default: { 78 | updateLocalStorage({ 79 | message: 'アップロードに失敗しました。' 80 | }) 81 | break 82 | } 83 | } 84 | } 85 | 86 | // Canvasに画像をセットして,必要部分のみ切り出す 87 | const renderImage = function (linkdata, base64Img, devicePixelRatio) { 88 | var rat = devicePixelRatio; 89 | var canvas = document.querySelector("#cav"); 90 | var pos_cropper = linkdata.cropperRect; 91 | var baseUri = linkdata.baseUri; 92 | var title = linkdata.title; 93 | var w = +pos_cropper.width; 94 | var h = +pos_cropper.height; 95 | canvas.width = rat * w; 96 | canvas.height = rat * h; 97 | 98 | var ctx = canvas.getContext('2d'); 99 | var img = new Image(); 100 | img.onload = function () { 101 | ctx.drawImage(img, rat * pos_cropper.orgX, rat * pos_cropper.orgY, rat * w, rat * h, 102 | 0, 0, rat * w, rat * h) 103 | const screenshot = canvas.toDataURL('image/png') 104 | keepMetaData( 105 | linkdata.aTagRects, 106 | linkdata.elementRects, 107 | linkdata.text, 108 | w, 109 | h, 110 | baseUri, 111 | title, 112 | rat, 113 | screenshot) 114 | uploadToSVGScreenshot({ 115 | devicePixelRatio: rat 116 | }) 117 | }; 118 | img.src = base64Img; 119 | }; 120 | 121 | const keepMetaData = (aTagRects, elementRects, text, width, height, baseUri, title, devicePixelRatio, base64Img) => { 122 | META = { aTagRects, elementRects, text, width, height, baseUri, title, devicePixelRatio, base64Img } 123 | } 124 | 125 | // ポップアップ画面から命令を受ける 126 | chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) { 127 | var opts = request.options; 128 | 129 | if (request.command === 'make-screen-shot') { 130 | // スクリーンショットの撮影 131 | var linkdata = opts.sitedata; 132 | chrome.tabs.captureVisibleTab({ format: 'png' }, function (dataUrl) { 133 | setBadgeCaptureCompleted() 134 | renderImage(linkdata, dataUrl, opts.dpr) 135 | }); 136 | } 137 | }); 138 | 139 | var initScreenShotMenu = () => { 140 | // ユーザーが閲覧中のページに専用の右クリックメニューを設ける 141 | // ウェブページ向け 142 | chrome.contextMenus.create({ 143 | title: 'Capture whole page', 144 | contexts: [ 145 | 'page', 146 | 'selection' 147 | ], 148 | onclick: function (clicked, tab) { 149 | clearBadge() 150 | chrome.tabs.sendRequest(tab.id, { 151 | event: 'capture-whole-page' 152 | }); 153 | } 154 | }) 155 | }; 156 | 157 | initScreenShotMenu(); 158 | 159 | chrome.tabs.onUpdated.addListener(function(tabId, info, tab) { 160 | if (info.status === 'complete') { 161 | chrome.tabs.sendRequest(tab.id, { 162 | event: 'updated-location-href' 163 | }); 164 | } 165 | }) 166 | })(); 167 | -------------------------------------------------------------------------------- /client/common.js: -------------------------------------------------------------------------------- 1 | // BrowserActionのBadgeをクリア 2 | const clearBadge = () => { 3 | chrome.browserAction.setBadgeText({ 'text': '' }) 4 | } 5 | 6 | const setBadgeCaptureCompleted = () => { 7 | chrome.browserAction.setBadgeBackgroundColor({ color: '#4abb0c' }) 8 | chrome.browserAction.setBadgeText({ text: '○' }) 9 | } 10 | 11 | const setBadgeUploadingToGyazo = () => { 12 | chrome.browserAction.setBadgeBackgroundColor({ color: '#4abb0c' }) 13 | chrome.browserAction.setBadgeText({ text: 'G' }) 14 | } 15 | 16 | const readOptions = () => { 17 | if (!localStorage.svgscreenshot_settings) return {} 18 | return JSON.parse(localStorage.svgscreenshot_settings) 19 | } 20 | 21 | // ブラウザ側でもa.href, titleを確認する 22 | var validateUrl = (url='') => { 23 | // http, https で始まるもののみOK 24 | var prot = url.split(':')[0].toLowerCase(); 25 | if (prot && (prot === 'http' || prot === 'https')) { 26 | // OK 27 | }else { 28 | return ''; 29 | } 30 | // <, > を除去 31 | url = url.replace(//g, ''); 32 | return url; 33 | }; 34 | 35 | var validateTitle = (title='') => { 36 | // <, > を除去 37 | title = title.replace(//g, ''); 38 | return title; 39 | }; 40 | 41 | const setAttributeNS = (elem, namespace, attrs) => { 42 | const keys = Object.keys(attrs) 43 | for (const key of keys) { 44 | elem.setAttributeNS(namespace || null, key, attrs[key]) 45 | } 46 | return elem 47 | } 48 | -------------------------------------------------------------------------------- /client/content_script.js: -------------------------------------------------------------------------------- 1 | const APP_PREFIX = 'dynamic_gazo'; 2 | const dynamicGazo = window.dynamicGazo 3 | const ESC = 27 4 | let flagMousedown = false 5 | 6 | const sendChromeMsg = (json, callback) => { 7 | chrome.runtime.sendMessage(json, callback); 8 | }; 9 | 10 | class ScreenShot { 11 | constructor () { 12 | this.CROP_BOX_SIZE = 150; 13 | this.uiInit(); 14 | this.positionLastRclick = [200, 200]; 15 | this.linkdata = null; 16 | this.tmp = { 17 | // 右クリックされた画像要素 18 | '$contextMenuImg': [] 19 | }; 20 | this.inlineViewer = null; 21 | 22 | // アプリケーションとしてSVG撮影を使う場合,アプリ名がセットされる 23 | this.app = null; 24 | } 25 | 26 | renderCropper (boxParams = []) { 27 | var self = this; 28 | self.initCropperMain(boxParams, null) 29 | } 30 | 31 | uiInit () { 32 | this.bindEvents(); 33 | } 34 | 35 | // 切り抜きボックス, a要素カバーボックス 36 | $genCropper () { 37 | var $cropper = $(`
`); 38 | $cropper.css({ 39 | top : 0, 40 | left : 0, 41 | width : this.CROP_BOX_SIZE, 42 | height: this.CROP_BOX_SIZE 43 | }); 44 | return $cropper; 45 | } 46 | 47 | // true : 表示中のウェブページをスクロール不可にする 48 | // false: 解除する 49 | fixHtml (fg) { 50 | var fg = fg || false; 51 | if (fg) { 52 | $('html').css({ 53 | height : '100%', 54 | width : '100%', 55 | overflow: 'hidden' 56 | }) 57 | }else { 58 | $('html').css({ 59 | height : '', 60 | width : '', 61 | overflow: 'auto' 62 | }) 63 | } 64 | } 65 | 66 | $showWrapper () { 67 | const $body = $('body') 68 | const $wrapper = $(`
`) 69 | $wrapper.css({ 70 | position: 'fixed', 71 | top: 0, 72 | left: 0, 73 | width: '100%', 74 | height: '100%', 75 | cursor: 'crosshair', 76 | zIndex: 2147483646 77 | }) 78 | $body.append($wrapper) 79 | return $wrapper 80 | } 81 | 82 | // 範囲指定のための長方形を表示する 83 | initCropperMain () { 84 | const self = this 85 | const $cropper = this.$genCropper() 86 | const $wrapper = this.$showWrapper() 87 | const startPosition = { 88 | left: 0, 89 | top: 0 90 | } 91 | 92 | $cropper[0].className = 'daiz-ss-cropper-main' 93 | $cropper[0].id = `${APP_PREFIX}-daiz-ss-cropper-main` 94 | 95 | $wrapper.on('mousedown', event => { 96 | startPosition.left = event.pageX 97 | startPosition.top = event.pageY 98 | $cropper.css({ 99 | left : startPosition.left - window.scrollX, 100 | top : startPosition.top - window.scrollY, 101 | width : 0, 102 | height: 0 103 | }) 104 | flagMousedown = true 105 | self.fixHtml(true) 106 | $('body').append($cropper) 107 | }) 108 | 109 | this.setMousemoveHandler($wrapper, $cropper, startPosition) 110 | this.setMousemoveHandler($cropper, $cropper, startPosition) 111 | 112 | $wrapper.on('mouseup', event => { 113 | const width = event.pageX - startPosition.left 114 | const height = event.pageY - startPosition.top 115 | if (width < 20 || height < 20) return 116 | $cropper.css({ width, height }) 117 | flagMousedown = false 118 | $wrapper.remove() 119 | self._setRects(false) 120 | }) 121 | 122 | $(window).on('keyup', event => { 123 | if (event.keyCode === ESC) self.clearCropper() 124 | }) 125 | } 126 | 127 | clearCropper () { 128 | flagMousedown = false 129 | this.clean() 130 | } 131 | 132 | setMousemoveHandler ($elem, $cropper, startPosition) { 133 | const self = this 134 | $elem.on('mousemove', event => { 135 | if (!flagMousedown) return 136 | $cropper.css({ 137 | width : event.pageX - startPosition.left, 138 | height: event.pageY - startPosition.top, 139 | }) 140 | self._setRects(true) 141 | }) 142 | } 143 | 144 | _setRects (simulate=false, _range=undefined) { 145 | var $cropper = $(`#${APP_PREFIX}-daiz-ss-cropper-main`) 146 | const range = _range || $cropper[0].getBoundingClientRect() 147 | if (range === undefined) return; 148 | this.removeCropper() 149 | 150 | if (simulate) { 151 | this.linkdata = this.setRects(range, simulate) 152 | } else { 153 | this.clean() 154 | // ページから不要なdivが消去されてからスクリーンショットを撮りたいので, 155 | // 1秒待ってから送信する 156 | window.setTimeout(() => { 157 | if (this.existCropUI()) { 158 | console.log('rep') 159 | this._setRects(false, range) 160 | return 161 | } 162 | this.linkdata = this.setRects(range, simulate) 163 | this.capture() 164 | }, 1) 165 | } 166 | } 167 | 168 | // ページ上で選択されている文字列を取得 169 | getSelectedText () { 170 | var self = this; 171 | var selection = window.getSelection(); 172 | var text = selection.toString(); 173 | return text; 174 | } 175 | 176 | setRects (range, simulate=false) { 177 | // this.fixHtml(true) 178 | let $cropperMain = null 179 | if (!simulate) { 180 | $cropperMain = $(this.removeCropperMain()) 181 | } 182 | 183 | const anchorsInArea = new dynamicGazo.AnchorsInArea(document) 184 | anchorsInArea.options.detail = true 185 | anchorsInArea.options.onlyInTopLayer = !simulate 186 | const aTags = anchorsInArea.find(range) 187 | 188 | let imgTags = [] 189 | if (!simulate) { 190 | // XXX: 要素が増えたら、共通化 191 | imgTags = this.correctPositions(anchorsInArea.find(range, 'img'), range) 192 | for (const imgTag of imgTags) { 193 | imgTag.css = {} 194 | imgTag.css['border-radius'] = jQuery(imgTag.ref).css('border-radius') || '0px' 195 | } 196 | } 197 | 198 | // リンク以外のテキスト: 199 | var text = this.getSelectedText(); 200 | $('#daiz-ss-cropper-main').attr('title', text); 201 | 202 | // リンク: 切り抜かれた形内のみ,aタグを覆えばよい 203 | var aTagRects = []; 204 | for (var i = 0; i < aTags.length; i++) { 205 | var aTag = aTags[i]; 206 | var rect = aTag.position 207 | if (rect !== undefined) { 208 | // リンク要素の位置と大きさに合わせて,長方形カバーを被せる 209 | const $cropper = this.$genCropper(); 210 | $cropper.css({ 211 | width : rect.width, 212 | height: rect.height, 213 | left : rect.left, 214 | top : rect.top 215 | }); 216 | var aid = `daiz-ss-a${i}`; 217 | var pos = this.correctPosition(rect, range); 218 | pos.id = aid; 219 | pos.href = aTag.url; 220 | pos.text = aTag.text; 221 | pos.fontSize = $(aTag.ref).css('font-size'); 222 | pos.fontFamily = $(aTag.ref).css('font-family'); 223 | 224 | $cropper.attr('title', aTag.url); 225 | $cropper.attr('id', aid); 226 | if (simulate) $('body').append($cropper); 227 | aTagRects.push(pos); 228 | } 229 | } 230 | 231 | // 切り取り領域 232 | var pos_cropper = { 233 | x : 0, 234 | y : 0, 235 | orgX : range.left, 236 | orgY : range.top, 237 | width : range.width, 238 | height: range.height 239 | }; 240 | 241 | var title = document.title || ''; 242 | if (title.length === 0) { 243 | // PDFページの場合,embedタグからファイル名を抽出して 244 | // titleとする 245 | var embeds = $('embed'); 246 | if (embeds.length > 0 && embeds[0].type === 'application/pdf') { 247 | var pdfPath = '/' + embeds[0].src; 248 | var toks = pdfPath.split('/'); 249 | title = toks[toks.length - 1]; 250 | } 251 | } 252 | 253 | var res = { 254 | cropperRect : pos_cropper, 255 | aTagRects : aTagRects, 256 | elementRects: { 257 | img: imgTags 258 | }, 259 | text : text, 260 | winW : window.innerWidth, 261 | winH : window.innerHeight, 262 | baseUri : window.location.href, 263 | title : title 264 | }; 265 | return res; 266 | } 267 | 268 | // aタグの位置補正 269 | // stageRectの左端,上端を基準とした距離表現に直す 270 | // aTagRect ⊂ stageRect は保証されている 271 | correctPosition (aTagRect, stageRect) { 272 | // XXX: scrollの扱いを詰める必要あり 273 | let res = {} 274 | const x1 = aTagRect.left - stageRect.left 275 | // var x2 = (aTagRect.left + aTagRect.width) - stageRect.left; 276 | const y1 = aTagRect.top - stageRect.top 277 | // var y2 = (aTagRect.top + aTagRect.height) - stageRect.top; 278 | res = { 279 | x : x1, 280 | y : y1, 281 | width : aTagRect.width, 282 | height: aTagRect.height 283 | } 284 | return res 285 | } 286 | 287 | correctPositions (rects, stageRect) { 288 | for (const rect of rects) { 289 | const {x, y} = this.correctPosition(rect.position, stageRect) 290 | rect.x = x 291 | rect.y = y 292 | } 293 | return rects 294 | } 295 | 296 | // 描画されている長方形カバーを全て消去 297 | removeCropper () { 298 | $('.daiz-ss-cropper').remove(); 299 | } 300 | 301 | getCropperMain () { 302 | return $(".daiz-ss-cropper-main")[0] 303 | } 304 | 305 | removeCropperMain () { 306 | const $elem = $(".daiz-ss-cropper-main") 307 | if ($elem.length === 0) return null 308 | const copy = $elem[0].cloneNode(true) 309 | $elem.remove(); 310 | return copy 311 | } 312 | 313 | capture (mode='capture') { 314 | var self = this 315 | var res = [] 316 | window.getSelection().removeAllRanges() 317 | 318 | // MacBook ProのRetinaディスプレイなどの高解像度な 319 | // ディスプレイを使用している場合は1より大きな値となる 320 | var rat = Math.max(window.devicePixelRatio, 1.0); 321 | if (self.linkdata !== null) { 322 | var appName = self.app; 323 | self.app = null; 324 | sendChromeMsg({ 325 | command: 'make-screen-shot', 326 | options: { 327 | sitedata: self.linkdata, 328 | mode: mode, 329 | scrapbox_box_id: null, 330 | app: appName, 331 | dpr: rat 332 | } 333 | }); 334 | } 335 | } 336 | 337 | clean () { 338 | if (!this.existCropUI()) return 339 | console.log('clean') 340 | this.removeCropperMain(); 341 | this.removeCropper(); 342 | $('#daiiz-wrapper').remove() 343 | this.fixHtml(false); 344 | } 345 | 346 | existCropUI () { 347 | const wrapperExist = $('#daiiz-wrapper').length > 0 348 | const cropperMainExist = $('.daiz-ss-cropper-main').length > 0 349 | const cropperExist = $('.daiz-ss-cropper').length > 0 350 | return wrapperExist || cropperMainExist || cropperExist 351 | } 352 | 353 | bindEvents () { 354 | var self = this; 355 | var $body = $('body'); 356 | 357 | // 画像上での右クリックを追跡 358 | $body.on('contextmenu', 'img', ev => { 359 | var $img = $(ev.target).closest('img'); 360 | this.tmp.$contextMenuImg = $img; 361 | }); 362 | 363 | $body.on('contextmenu', '.card-thumbnail', ev => { 364 | var $img = $(ev.target).closest('.card-area').find('.card-img'); 365 | this.app = 'linkcard'; 366 | self.tmp.$contextMenuImg = $img; 367 | }); 368 | 369 | // ページでの右クリックを検出 370 | $(window).bind('contextmenu', (e) => { 371 | this.positionLastRclick = [e.clientX, e.clientY]; 372 | }); 373 | 374 | // コンテキストメニュー(右クリックメニュー)が押された通知をbackgroundページから受け取る 375 | chrome.extension.onRequest.addListener((request, sender, sendResponse) => { 376 | var re = request.event; 377 | if (re === 'capture-whole-page') { 378 | // 撮影領域を選択するやつを表示 379 | const range = { 380 | left: 0, 381 | right: window.innerWidth, 382 | top: 0, 383 | bottom: window.innerHeight, 384 | width: window.innerWidth, 385 | height: window.innerHeight 386 | } 387 | this.linkdata = this.setRects(range, false) 388 | this.capture() 389 | } else if (re === 'capture-range') { 390 | this.renderCropper() 391 | } else if (re === 'cancel-capture-range') { 392 | this.clean() 393 | } 394 | }); 395 | 396 | $body.on('click', '.card-close', ev => { 397 | $('.card-area').remove(); 398 | }); 399 | } 400 | } 401 | var ss = new ScreenShot(); 402 | 403 | chrome.extension.onRequest.addListener((request, sender, sendResponse) => { 404 | var mark = "chrome-ext"; 405 | if (request.event === 'updated-location-href') { 406 | var $body = $('body'); 407 | if ($body.length > 0) { 408 | $body[0].dataset.stat_daiz_svgss = mark; 409 | } 410 | if (ss.inlineViewer === null) { 411 | ss.inlineViewer = new InlineViewer(); 412 | } 413 | } 414 | }) 415 | -------------------------------------------------------------------------------- /client/create_svg.js: -------------------------------------------------------------------------------- 1 | const sourceStyle = [ 2 | `.source text { 3 | fill: #888888; 4 | font-size: 11px; 5 | font-weight: 400; 6 | text-decoration: none; 7 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; 8 | }`, 9 | `.source text:hover { 10 | text-decoration: underline; 11 | fill: #2962FF; 12 | }` 13 | ] 14 | 15 | const createSVGTag = ( 16 | {aTagRects, elementRects, text, width, height, baseUri, title, base64Img}) => { 17 | const externals = [] 18 | 19 | // imgs 20 | const imgs = elementRects.img 21 | for (const imgRect of imgs) { 22 | const {url, position} = imgRect 23 | // Gyazo以外の画像は無視 24 | if (url.match(/gyazo\.com\//i) === null) continue 25 | // 静止画像の場合は無視 26 | if (url.match(/\.(svg|png|jpe?g|bmp)$/i) !== null) continue 27 | externals.push({ 28 | url, 29 | x: imgRect.x, 30 | y: imgRect.y, 31 | width: position.width, 32 | height: position.height, 33 | type: 'img' 34 | }) 35 | } 36 | 37 | // ページ内リンク 38 | for (const anchor of aTagRects) { 39 | externals.push({ 40 | url: validateUrl(anchor.href), 41 | x: anchor.x, 42 | y: anchor.y, 43 | width: anchor.width, 44 | height: anchor.height, 45 | text: validateTitle(anchor.text) 46 | }) 47 | } 48 | 49 | // 出典 50 | externals.push({ 51 | url: validateUrl(baseUri), 52 | text: validateTitle(title), 53 | className: 'source', 54 | x: 4, 55 | y: height - 4 56 | }) 57 | 58 | const svgTagText = dynamicGazo.svgize.createSvg(base64Img, { 59 | width, height, 60 | className: 'svg-screenshot', 61 | dataset: { 62 | url: validateUrl(baseUri), 63 | title: validateTitle(title) 64 | }, 65 | externals, 66 | style: sourceStyle 67 | }) 68 | 69 | return {tagText: svgTagText, viewBox: `0 0 ${width} ${height}`} 70 | } 71 | -------------------------------------------------------------------------------- /client/inline_viewer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ウェブページ中で DynamicGazo のプレビューを展開する 3 | * 対象画像をホバーしたときにSVGコンテンツを重ねて表示する 4 | */ 5 | class InlineViewer { 6 | constructor () { 7 | this.appUrl = (window.dynamicGazo.env === 'production') ? 8 | 'https://svgscreenshot.appspot.com' : 'http://localhost:8080' 9 | this.gyazo = 'https://gyazo.com' 10 | this.svgScreenShotUrlPatterns = [ 11 | `${this.appUrl}/c/x/(.+)`, 12 | `${this.appUrl}/thumb/(.+)` 13 | ] 14 | /* 直近で検出した画像のID */ 15 | this.latestImageId = null 16 | this.hideAllSVGScreenShots() 17 | this.bindEvents() 18 | } 19 | 20 | detectImageId (src, urlPatterns) { 21 | let imgId = null; 22 | for (let i = 0; i < urlPatterns.length; i++) { 23 | let pattern = urlPatterns[i]; 24 | let reg = new RegExp(pattern); 25 | let matched = src.match(reg); 26 | if (matched && matched.length >= 2) { 27 | imgId = matched[1].split('#')[0].split('.')[0] 28 | break; 29 | } 30 | } 31 | if (imgId === null) return null; 32 | if (imgId.indexOf('/') !== -1) return null; 33 | return imgId; 34 | } 35 | 36 | $getCover (cid='', $img) { 37 | // cid is cover-id 38 | var coverId = 'daiz-ss-iv-cover-c-' + cid; 39 | var pageX = window.pageXOffset; 40 | var pageY = window.pageYOffset; 41 | 42 | var $cover = $(`#${coverId}`); 43 | var newCover = false; 44 | 45 | // 存在しない場合は新規作成する 46 | if ($cover.length === 0) { 47 | newCover = true; 48 | var optionClassName = ''; 49 | if (window.location.host === 'gyazo.com') { 50 | optionClassName = 'gyazo-com' 51 | } 52 | $cover = $(`
53 |
54 |
55 |
`); 56 | 57 | $cover.css({ 58 | width: $img.width(), 59 | height: $img.height(), 60 | display: 'none' 61 | }); 62 | } 63 | 64 | var imgRect = $img[0].getBoundingClientRect(); 65 | $cover.css({ 66 | left: imgRect.left + pageX, 67 | top: imgRect.top + pageY, 68 | cursor: $img.css('cursor') || 'default' 69 | }); 70 | 71 | return [$cover, newCover]; 72 | } 73 | 74 | // SVGコンテンツを表示する 75 | renderSVGScreenShot ($cover, cid='') { 76 | var cover = $cover[0] 77 | var coverWidth = $cover.width() 78 | var coverHeight = $cover.height() 79 | var $svgArea = $cover.find('.daiz-ss-iv-svg') 80 | var svgUrl = `${this.appUrl}/d/s/${cid}` 81 | 82 | $.ajax({ 83 | url: svgUrl, 84 | method: "POST", 85 | dataType: "json" 86 | }).success(data => { 87 | let svgTag = data.svg_tag; 88 | let appName = data.app_name || null; 89 | if (svgTag.length === 0) return; 90 | var doc = new DOMParser().parseFromString(svgTag, 'application/xml'); 91 | $svgArea[0].appendChild(cover.ownerDocument.importNode(doc.documentElement, true)); 92 | var svg = cover.querySelector('svg.svg-screenshot'); 93 | var orgUrl = data.url; 94 | var title = data.title; 95 | // SVGレイヤーのサイズを設定 96 | // viewBox.width, viewBox.height: SVGのオリジナルサイズ 97 | // coverWidth, coverHeight: サムネイルのサイズ 98 | svg.setAttribute('width', coverWidth); 99 | svg.setAttribute('height', coverHeight); 100 | $cover.show(); 101 | }); 102 | } 103 | 104 | // SVGコンテンツを最新のサムネイルのサイズに合わせる 105 | updateSVGScreenShotSize ($cover, $img) { 106 | if ($cover.find('.daiz-ss-iv-svg')[0].innerHTML.trim() === '') return; 107 | 108 | var w = $img.width(); 109 | var h = $img.height(); 110 | $cover.css({ 111 | width: w, 112 | height: h 113 | }); 114 | var svg = $cover[0].querySelector('svg.svg-screenshot'); 115 | if (svg) { 116 | svg.setAttribute('width', w); 117 | svg.setAttribute('height', h); 118 | } 119 | $cover.show(); 120 | } 121 | 122 | // 全てのcoverを非表示にする 123 | hideAllSVGScreenShots () { 124 | // 既存の消し忘れカバーを消す 125 | $('.daiz-ss-iv-cover').css('display', 'none'); 126 | } 127 | 128 | bindEvents () { 129 | var self = this; 130 | var $body = $('body'); 131 | 132 | const showLinkLayer = e => { 133 | const $img = $(e.target).closest('img') 134 | 135 | // 対象画像であるかを確認 136 | const src = decodeURIComponent($img[0].src) 137 | const imageId = self.detectImageId(src, self.svgScreenShotUrlPatterns) 138 | 139 | if (imageId === null) return 140 | if (imageId !== this.latestImageId) { 141 | this.latestImageId = imageId 142 | } 143 | 144 | self.hideAllSVGScreenShots() 145 | var coverInfo = self.$getCover(imageId, $img) 146 | var $cover = coverInfo[0] 147 | if (coverInfo[1]) { 148 | // 新規作成されたカバー 149 | $cover.on('click', event => { 150 | const className = event.target.className.baseVal 151 | if (className !== 'svg-screenshot') return 152 | $cover.hide() 153 | $img.trigger('click') 154 | }) 155 | 156 | $body.append($cover) 157 | self.renderSVGScreenShot($cover, imageId) 158 | }else { 159 | self.updateSVGScreenShotSize($cover, $img) 160 | } 161 | } 162 | 163 | // 画像mouseenter時 164 | $body.on('mouseenter', 'img', e => { 165 | showLinkLayer(e) 166 | }); 167 | 168 | // 画像mouseleave時 169 | $body.on('mouseleave', '.daiz-ss-iv-cover', e => { 170 | var $cover = $(e.target).closest('.daiz-ss-iv-cover'); 171 | $cover.hide(); 172 | }); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /client/options.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | const getOptions = () => { 3 | return JSON.parse(localStorage.svgscreenshot_settings) 4 | } 5 | 6 | const saveOptions = function (obj) { 7 | localStorage.svgscreenshot_settings = JSON.stringify(obj) 8 | } 9 | 10 | if (!localStorage.svgscreenshot_settings) { 11 | saveOptions({ 12 | useGyazo: "no", 13 | gyazoHashtag: "#SVGScreenshot" 14 | }) 15 | }else { 16 | const {useGyazo, gyazoHashtag} = getOptions() 17 | $('#use_gyazo')[0].checked = useGyazo === 'yes' 18 | $('#gyazo_hashtag')[0].value = gyazoHashtag 19 | } 20 | 21 | $('#btn_save').on('click', () => { 22 | const useGyazo = ($('#use_gyazo')[0].checked) ? 'yes' : 'no' 23 | const gyazoHashtag = $('#gyazo_hashtag')[0].value 24 | saveOptions({useGyazo, gyazoHashtag}) 25 | window.close() 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /client/popup.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | const replaceToDevUrls = () => { 3 | if (window.dynamicGazo.env === 'production') return 4 | const targets = [ 5 | '#open', 6 | '#y-collection', 7 | '#login', 8 | '#collection' 9 | ] 10 | for (const target of targets) { 11 | const url = document.querySelector(target).href 12 | document.querySelector(target).href = url.replace( 13 | /^https\:\/\/svgscreenshot\.appspot\.com/, 'http://localhost:8080') 14 | } 15 | } 16 | 17 | const setCancelEvents = () => { 18 | document.querySelector('#img').addEventListener('click', () => { 19 | closeWindow() 20 | }) 21 | 22 | const aTags = document.querySelectorAll('a') 23 | for (const a of aTags) { 24 | a.addEventListener('click', () => { closeWindow() }) 25 | } 26 | } 27 | 28 | const setGyazoCollectionLink = () => { 29 | const {useGyazo, gyazoHashtag} = readOptions() 30 | const gayzoCollection = document.querySelector('#gyazo-collection') 31 | if (useGyazo === 'yes') { 32 | if (gyazoHashtag.length === 0) return 33 | gayzoCollection.href = `https://gyazo.com/search/${encodeURIComponent(gyazoHashtag)}` 34 | } else { 35 | gayzoCollection.remove() 36 | } 37 | } 38 | 39 | const itemUrl = (url) => { 40 | if (!url) return '' 41 | if (window.dynamicGazo.env === 'production') return url 42 | return url.replace(/^https\:\/\/svgscreenshot\.appspot\.com/, 'http://localhost:8080') 43 | } 44 | 45 | const openN = () => { 46 | document.querySelector('#n').style.display = 'block'; 47 | document.querySelector('#y').style.display = 'none'; 48 | } 49 | 50 | const openY = () => { 51 | document.querySelector('#y').style.display = 'block'; 52 | document.querySelector('#n').style.display = 'none'; 53 | } 54 | 55 | window.addEventListener('load', function () { 56 | document.querySelector('#open').href = itemUrl(localStorage.item_url) 57 | const thumbnail = document.querySelector('#img') 58 | const imgUrl = localStorage.item_img.replace(/\/c\/x\//, '/c/xo/') || '' 59 | thumbnail.setAttribute('src', imgUrl) 60 | thumbnail.closest('div.copy-btn').dataset.clipboardText = itemUrl(imgUrl) 61 | var err = localStorage.is_error || 'ようこそ' 62 | if (err !== 'y') { 63 | // キャプチャ失敗 64 | document.querySelector('#msg').innerText = err 65 | openN() 66 | }else { 67 | new Clipboard('.copy-btn') 68 | openY() 69 | } 70 | replaceToDevUrls() 71 | setGyazoCollectionLink() 72 | setCancelEvents() 73 | }, false) 74 | 75 | document.querySelector('#open').addEventListener('click', function () { 76 | clearBadge(); 77 | }, false); 78 | 79 | document.querySelector('#login').addEventListener('click', function () { 80 | clearBadge(); 81 | }, false); 82 | 83 | // 範囲選択による撮影モード 84 | chrome.tabs.getSelected(null, function (tab) { 85 | chrome.tabs.sendRequest(tab.id, { 86 | event: 'capture-range' 87 | }) 88 | }) 89 | 90 | const closeWindow = () => { 91 | chrome.tabs.getSelected(null, function (tab) { 92 | chrome.tabs.sendRequest(tab.id, { 93 | event: 'cancel-capture-range' 94 | }) 95 | }) 96 | window.close() 97 | } 98 | 99 | // register elements 100 | for (const Elem of dynamicGazo.elements) { 101 | window.customElements.define(Elem.is, Elem) 102 | } 103 | })() 104 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dynamic-gazo", 3 | "version": "1.1.0", 4 | "main": "index.js", 5 | "engine": { 6 | "node": "8.7.0" 7 | }, 8 | "repository": "git@github.com:daiz713/DynamicGazo.git", 9 | "author": "daiiz ", 10 | "license": "MIT", 11 | "scripts": { 12 | "build": "./node_modules/.bin/run-s build:**", 13 | "build:babel": "./node_modules/.bin/babel client/ --out-dir chrome/build/ --minified --source-maps false", 14 | "build:browserify": "NODE_ENV=production ./node_modules/.bin/browserify -t [ babelify ] -t envify src/index.js -o chrome/build/bundle.js -v", 15 | "build:package": "zip -r releases/chrome.zip chrome", 16 | "watch": "./node_modules/.bin/run-p watch:**", 17 | "watch:babel": "npm run build:babel -- --watch", 18 | "watch:browserify": "NODE_ENV=production ./node_modules/.bin/watchify -t [ babelify ] -t envify src/index.js -o chrome/build/bundle.js -v", 19 | "watch-dev": "./node_modules/.bin/run-p watch-dev:**", 20 | "watch-dev:babel": "npm run build:babel -- --watch", 21 | "watch-dev:browserify": "NODE_ENV=development ./node_modules/.bin/watchify -t [ babelify ] -t envify src/index.js -o chrome/build/bundle.js -v" 22 | }, 23 | "dependencies": { 24 | "@daiiz/dpi-aware-image": "^2.0.7", 25 | "anchors-in-area": "^1.0.21", 26 | "axios": "^0.18.1", 27 | "img-svgize": "^1.0.0", 28 | "png-dpi-reader-writer": "^0.1.0" 29 | }, 30 | "devDependencies": { 31 | "@babel/cli": "^7.7.4", 32 | "@babel/plugin-transform-runtime": "^7.7.4", 33 | "babelify": "^7.3.0", 34 | "browserify": "^14.4.0", 35 | "envify": "^4.1.0", 36 | "npm-run-all": "^4.0.2", 37 | "watchify": "^3.11.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /releases/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daiiz/svg-screenshot/48ceb573b1a4275abd09762c589abf06e4513b0b/releases/.keep -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const AnchorsInArea = require('anchors-in-area') 2 | const axios = require('axios') 3 | const {convertToByteArray, convertToDataURI, writePngDpi} = require('png-dpi-reader-writer') 4 | const {DpiAwareImage} = require('@daiiz/dpi-aware-image') 5 | const svgize = require('img-svgize') 6 | 7 | window.dynamicGazo = { 8 | elements: [ 9 | DpiAwareImage 10 | ], 11 | env: process.env.NODE_ENV, 12 | appOrigin: (process.env.NODE_ENV === 'production') ? 13 | 'https://svgscreenshot.appspot.com' : 'http://localhost:8080' 14 | } 15 | 16 | dynamicGazo.AnchorsInArea = AnchorsInArea 17 | dynamicGazo.svgize = svgize 18 | 19 | dynamicGazo.addPhysChunk = (dataURI, dpr=1) => { 20 | const orgByteArray = convertToByteArray(dataURI) 21 | try { 22 | const genByteArray = writePngDpi(orgByteArray, dpr * 72) 23 | return convertToDataURI(genByteArray) 24 | } catch (err) { 25 | return orgByteArray 26 | } 27 | } 28 | 29 | // upload to SVGScreenshot 30 | dynamicGazo.uploadToDynamicGazo = async ({svg, title, referer, base64Img, devicePixelRatio}) => { 31 | let res 32 | try { 33 | res = await axios.post(`${dynamicGazo.appOrigin}/api/uploadsvg`, { 34 | svg: svg.tagText, 35 | base64png: base64Img, 36 | orgurl: referer, 37 | title, 38 | viewbox: svg.viewBox, 39 | public: 'yes', 40 | dpr: devicePixelRatio 41 | }) 42 | } catch (err) { 43 | console.error(err) 44 | } 45 | return res 46 | } 47 | 48 | // upload to Gyazo 49 | dynamicGazo.uploadToGyazo = async ( 50 | {scale, image, referer, title, svgScreenshotImageId, hashTag}) => { 51 | const apiEndpoint = `https://upload.gyazo.com/api/upload/easy_auth` 52 | const clientId = 'a9544994509725a7ecceb7381661274751b5b31f006c7788c1d88517c13d1ebe' 53 | if (dynamicGazo.env !== 'production') return 54 | 55 | const dynamicGazoUrl = `${dynamicGazo.appOrigin}/x/${svgScreenshotImageId}` 56 | const formdata = new window.FormData() 57 | formdata.append('client_id', clientId) 58 | formdata.append('image_url', image) 59 | formdata.append('title', title) 60 | formdata.append('referer_url', referer) 61 | formdata.append('scale', scale) 62 | formdata.append('desc', `\n${dynamicGazoUrl}\n${hashTag}`) 63 | 64 | const response = await window.fetch(apiEndpoint, { 65 | method: 'POST', 66 | body: formdata, 67 | credentials: 'include' 68 | }) 69 | const _data = await response.json() 70 | 71 | const data = await window.fetch(_data.get_image_url, { 72 | method: 'GET', 73 | credentials: 'include' 74 | }) 75 | const gyazoImageId = data.url.split('gyazo.com/')[1] 76 | 77 | chrome.tabs.create({ 78 | url: data.url, 79 | active: false 80 | }, null) 81 | return gyazoImageId 82 | } 83 | --------------------------------------------------------------------------------