").attr("role","tooltip").addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||"")),s=i.uniqueId().attr("id");return e("
").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),this.tooltips[s]={element:t,tooltip:i}},_find:function(e){var t=e.data("ui-tooltip-id");return t?this.tooltips[t]:null},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(i,s){var n=e.Event("blur"),a=s.element;n.target=n.currentTarget=a[0],t.close(n,!0),e("#"+i).remove(),a.data("ui-tooltip-title")&&(a.attr("title")||a.attr("title",a.data("ui-tooltip-title")),a.removeData("ui-tooltip-title"))}),this.liveRegion.remove()}})});
\ No newline at end of file
diff --git a/public/editor/jquery-ui-1.11.4.custom/jquery-ui.structure.css b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.structure.css
new file mode 100755
index 0000000..dddd12b
--- /dev/null
+++ b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.structure.css
@@ -0,0 +1,690 @@
+/*!
+ * jQuery UI CSS Framework 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+ display: none;
+}
+.ui-helper-hidden-accessible {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+.ui-helper-reset {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ outline: 0;
+ line-height: 1.3;
+ text-decoration: none;
+ font-size: 100%;
+ list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+ content: "";
+ display: table;
+ border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+ clear: both;
+}
+.ui-helper-clearfix {
+ min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ left: 0;
+ position: absolute;
+ opacity: 0;
+ filter:Alpha(Opacity=0); /* support: IE8 */
+}
+
+.ui-front {
+ z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+ cursor: default !important;
+}
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+ display: block;
+ text-indent: -99999px;
+ overflow: hidden;
+ background-repeat: no-repeat;
+}
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+.ui-sortable-handle {
+ -ms-touch-action: none;
+ touch-action: none;
+}
+.ui-accordion .ui-accordion-header {
+ display: block;
+ cursor: pointer;
+ position: relative;
+ margin: 2px 0 0 0;
+ padding: .5em .5em .5em .7em;
+ min-height: 0; /* support: IE7 */
+ font-size: 100%;
+}
+.ui-accordion .ui-accordion-icons {
+ padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-icons .ui-accordion-icons {
+ padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+ position: absolute;
+ left: .5em;
+ top: 50%;
+ margin-top: -8px;
+}
+.ui-accordion .ui-accordion-content {
+ padding: 1em 2.2em;
+ border-top: 0;
+ overflow: auto;
+}
+.ui-autocomplete {
+ position: absolute;
+ top: 0;
+ left: 0;
+ cursor: default;
+}
+.ui-button {
+ display: inline-block;
+ position: relative;
+ padding: 0;
+ line-height: normal;
+ margin-right: .1em;
+ cursor: pointer;
+ vertical-align: middle;
+ text-align: center;
+ overflow: visible; /* removes extra width in IE */
+}
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+ text-decoration: none;
+}
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+ width: 2.2em;
+}
+/* button elements seem to need a little more width */
+button.ui-button-icon-only {
+ width: 2.4em;
+}
+.ui-button-icons-only {
+ width: 3.4em;
+}
+button.ui-button-icons-only {
+ width: 3.7em;
+}
+
+/* button text element */
+.ui-button .ui-button-text {
+ display: block;
+ line-height: normal;
+}
+.ui-button-text-only .ui-button-text {
+ padding: .4em 1em;
+}
+.ui-button-icon-only .ui-button-text,
+.ui-button-icons-only .ui-button-text {
+ padding: .4em;
+ text-indent: -9999999px;
+}
+.ui-button-text-icon-primary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+ padding: .4em 1em .4em 2.1em;
+}
+.ui-button-text-icon-secondary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+ padding: .4em 2.1em .4em 1em;
+}
+.ui-button-text-icons .ui-button-text {
+ padding-left: 2.1em;
+ padding-right: 2.1em;
+}
+/* no icon support for input elements, provide padding by default */
+input.ui-button {
+ padding: .4em 1em;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon,
+.ui-button-text-icon-primary .ui-icon,
+.ui-button-text-icon-secondary .ui-icon,
+.ui-button-text-icons .ui-icon,
+.ui-button-icons-only .ui-icon {
+ position: absolute;
+ top: 50%;
+ margin-top: -8px;
+}
+.ui-button-icon-only .ui-icon {
+ left: 50%;
+ margin-left: -8px;
+}
+.ui-button-text-icon-primary .ui-button-icon-primary,
+.ui-button-text-icons .ui-button-icon-primary,
+.ui-button-icons-only .ui-button-icon-primary {
+ left: .5em;
+}
+.ui-button-text-icon-secondary .ui-button-icon-secondary,
+.ui-button-text-icons .ui-button-icon-secondary,
+.ui-button-icons-only .ui-button-icon-secondary {
+ right: .5em;
+}
+
+/* button sets */
+.ui-buttonset {
+ margin-right: 7px;
+}
+.ui-buttonset .ui-button {
+ margin-left: 0;
+ margin-right: -.3em;
+}
+
+/* workarounds */
+/* reset extra padding in Firefox, see h5bp.com/l */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+ border: 0;
+ padding: 0;
+}
+.ui-datepicker {
+ width: 17em;
+ padding: .2em .2em 0;
+ display: none;
+}
+.ui-datepicker .ui-datepicker-header {
+ position: relative;
+ padding: .2em 0;
+}
+.ui-datepicker .ui-datepicker-prev,
+.ui-datepicker .ui-datepicker-next {
+ position: absolute;
+ top: 2px;
+ width: 1.8em;
+ height: 1.8em;
+}
+.ui-datepicker .ui-datepicker-prev-hover,
+.ui-datepicker .ui-datepicker-next-hover {
+ top: 1px;
+}
+.ui-datepicker .ui-datepicker-prev {
+ left: 2px;
+}
+.ui-datepicker .ui-datepicker-next {
+ right: 2px;
+}
+.ui-datepicker .ui-datepicker-prev-hover {
+ left: 1px;
+}
+.ui-datepicker .ui-datepicker-next-hover {
+ right: 1px;
+}
+.ui-datepicker .ui-datepicker-prev span,
+.ui-datepicker .ui-datepicker-next span {
+ display: block;
+ position: absolute;
+ left: 50%;
+ margin-left: -8px;
+ top: 50%;
+ margin-top: -8px;
+}
+.ui-datepicker .ui-datepicker-title {
+ margin: 0 2.3em;
+ line-height: 1.8em;
+ text-align: center;
+}
+.ui-datepicker .ui-datepicker-title select {
+ font-size: 1em;
+ margin: 1px 0;
+}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+ width: 45%;
+}
+.ui-datepicker table {
+ width: 100%;
+ font-size: .9em;
+ border-collapse: collapse;
+ margin: 0 0 .4em;
+}
+.ui-datepicker th {
+ padding: .7em .3em;
+ text-align: center;
+ font-weight: bold;
+ border: 0;
+}
+.ui-datepicker td {
+ border: 0;
+ padding: 1px;
+}
+.ui-datepicker td span,
+.ui-datepicker td a {
+ display: block;
+ padding: .2em;
+ text-align: right;
+ text-decoration: none;
+}
+.ui-datepicker .ui-datepicker-buttonpane {
+ background-image: none;
+ margin: .7em 0 0 0;
+ padding: 0 .2em;
+ border-left: 0;
+ border-right: 0;
+ border-bottom: 0;
+}
+.ui-datepicker .ui-datepicker-buttonpane button {
+ float: right;
+ margin: .5em .2em .4em;
+ cursor: pointer;
+ padding: .2em .6em .3em .6em;
+ width: auto;
+ overflow: visible;
+}
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
+ float: left;
+}
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi {
+ width: auto;
+}
+.ui-datepicker-multi .ui-datepicker-group {
+ float: left;
+}
+.ui-datepicker-multi .ui-datepicker-group table {
+ width: 95%;
+ margin: 0 auto .4em;
+}
+.ui-datepicker-multi-2 .ui-datepicker-group {
+ width: 50%;
+}
+.ui-datepicker-multi-3 .ui-datepicker-group {
+ width: 33.3%;
+}
+.ui-datepicker-multi-4 .ui-datepicker-group {
+ width: 25%;
+}
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
+ border-left-width: 0;
+}
+.ui-datepicker-multi .ui-datepicker-buttonpane {
+ clear: left;
+}
+.ui-datepicker-row-break {
+ clear: both;
+ width: 100%;
+ font-size: 0;
+}
+
+/* RTL support */
+.ui-datepicker-rtl {
+ direction: rtl;
+}
+.ui-datepicker-rtl .ui-datepicker-prev {
+ right: 2px;
+ left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next {
+ left: 2px;
+ right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-prev:hover {
+ right: 1px;
+ left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next:hover {
+ left: 1px;
+ right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane {
+ clear: right;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button {
+ float: left;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
+.ui-datepicker-rtl .ui-datepicker-group {
+ float: right;
+}
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
+ border-right-width: 0;
+ border-left-width: 1px;
+}
+.ui-menu {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ display: block;
+ outline: none;
+}
+.ui-menu .ui-menu {
+ position: absolute;
+}
+.ui-menu .ui-menu-item {
+ position: relative;
+ margin: 0;
+ padding: 3px 1em 3px .4em;
+ cursor: pointer;
+ min-height: 0; /* support: IE7 */
+ /* support: IE10, see #8844 */
+ list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
+}
+.ui-menu .ui-menu-divider {
+ margin: 5px 0;
+ height: 0;
+ font-size: 0;
+ line-height: 0;
+ border-width: 1px 0 0 0;
+}
+.ui-menu .ui-state-focus,
+.ui-menu .ui-state-active {
+ margin: -1px;
+}
+
+/* icon support */
+.ui-menu-icons {
+ position: relative;
+}
+.ui-menu-icons .ui-menu-item {
+ padding-left: 2em;
+}
+
+/* left-aligned */
+.ui-menu .ui-icon {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: .2em;
+ margin: auto 0;
+}
+
+/* right-aligned */
+.ui-menu .ui-menu-icon {
+ left: auto;
+ right: 0;
+}
+.ui-progressbar {
+ height: 2em;
+ text-align: left;
+ overflow: hidden;
+}
+.ui-progressbar .ui-progressbar-value {
+ margin: -1px;
+ height: 100%;
+}
+.ui-progressbar .ui-progressbar-overlay {
+ background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
+ height: 100%;
+ filter: alpha(opacity=25); /* support: IE8 */
+ opacity: 0.25;
+}
+.ui-progressbar-indeterminate .ui-progressbar-value {
+ background-image: none;
+}
+.ui-selectmenu-menu {
+ padding: 0;
+ margin: 0;
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: none;
+}
+.ui-selectmenu-menu .ui-menu {
+ overflow: auto;
+ /* Support: IE7 */
+ overflow-x: hidden;
+ padding-bottom: 1px;
+}
+.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
+ font-size: 1em;
+ font-weight: bold;
+ line-height: 1.5;
+ padding: 2px 0.4em;
+ margin: 0.5em 0 0 0;
+ height: auto;
+ border: 0;
+}
+.ui-selectmenu-open {
+ display: block;
+}
+.ui-selectmenu-button {
+ display: inline-block;
+ overflow: hidden;
+ position: relative;
+ text-decoration: none;
+ cursor: pointer;
+}
+.ui-selectmenu-button span.ui-icon {
+ right: 0.5em;
+ left: auto;
+ margin-top: -8px;
+ position: absolute;
+ top: 50%;
+}
+.ui-selectmenu-button span.ui-selectmenu-text {
+ text-align: left;
+ padding: 0.4em 2.1em 0.4em 1em;
+ display: block;
+ line-height: 1.4;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.ui-slider {
+ position: relative;
+ text-align: left;
+}
+.ui-slider .ui-slider-handle {
+ position: absolute;
+ z-index: 2;
+ width: 1.2em;
+ height: 1.2em;
+ cursor: default;
+ -ms-touch-action: none;
+ touch-action: none;
+}
+.ui-slider .ui-slider-range {
+ position: absolute;
+ z-index: 1;
+ font-size: .7em;
+ display: block;
+ border: 0;
+ background-position: 0 0;
+}
+
+/* support: IE8 - See #6727 */
+.ui-slider.ui-state-disabled .ui-slider-handle,
+.ui-slider.ui-state-disabled .ui-slider-range {
+ filter: inherit;
+}
+
+.ui-slider-horizontal {
+ height: .8em;
+}
+.ui-slider-horizontal .ui-slider-handle {
+ top: -.3em;
+ margin-left: -.6em;
+}
+.ui-slider-horizontal .ui-slider-range {
+ top: 0;
+ height: 100%;
+}
+.ui-slider-horizontal .ui-slider-range-min {
+ left: 0;
+}
+.ui-slider-horizontal .ui-slider-range-max {
+ right: 0;
+}
+
+.ui-slider-vertical {
+ width: .8em;
+ height: 100px;
+}
+.ui-slider-vertical .ui-slider-handle {
+ left: -.3em;
+ margin-left: 0;
+ margin-bottom: -.6em;
+}
+.ui-slider-vertical .ui-slider-range {
+ left: 0;
+ width: 100%;
+}
+.ui-slider-vertical .ui-slider-range-min {
+ bottom: 0;
+}
+.ui-slider-vertical .ui-slider-range-max {
+ top: 0;
+}
+.ui-spinner {
+ position: relative;
+ display: inline-block;
+ overflow: hidden;
+ padding: 0;
+ vertical-align: middle;
+}
+.ui-spinner-input {
+ border: none;
+ background: none;
+ color: inherit;
+ padding: 0;
+ margin: .2em 0;
+ vertical-align: middle;
+ margin-left: .4em;
+ margin-right: 22px;
+}
+.ui-spinner-button {
+ width: 16px;
+ height: 50%;
+ font-size: .5em;
+ padding: 0;
+ margin: 0;
+ text-align: center;
+ position: absolute;
+ cursor: default;
+ display: block;
+ overflow: hidden;
+ right: 0;
+}
+/* more specificity required here to override default borders */
+.ui-spinner a.ui-spinner-button {
+ border-top: none;
+ border-bottom: none;
+ border-right: none;
+}
+/* vertically center icon */
+.ui-spinner .ui-icon {
+ position: absolute;
+ margin-top: -8px;
+ top: 50%;
+ left: 0;
+}
+.ui-spinner-up {
+ top: 0;
+}
+.ui-spinner-down {
+ bottom: 0;
+}
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+ /* need to fix icons sprite */
+ background-position: -65px -16px;
+}
+.ui-tabs {
+ position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+ padding: .2em;
+}
+.ui-tabs .ui-tabs-nav {
+ margin: 0;
+ padding: .2em .2em 0;
+}
+.ui-tabs .ui-tabs-nav li {
+ list-style: none;
+ float: left;
+ position: relative;
+ top: 0;
+ margin: 1px .2em 0 0;
+ border-bottom-width: 0;
+ padding: 0;
+ white-space: nowrap;
+}
+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
+ float: left;
+ padding: .5em 1em;
+ text-decoration: none;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+ margin-bottom: -1px;
+ padding-bottom: 1px;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
+ cursor: text;
+}
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+ cursor: pointer;
+}
+.ui-tabs .ui-tabs-panel {
+ display: block;
+ border-width: 0;
+ padding: 1em 1.4em;
+ background: none;
+}
+.ui-tooltip {
+ padding: 8px;
+ position: absolute;
+ z-index: 9999;
+ max-width: 300px;
+ -webkit-box-shadow: 0 0 5px #aaa;
+ box-shadow: 0 0 5px #aaa;
+}
+body .ui-tooltip {
+ border-width: 2px;
+}
diff --git a/public/editor/jquery-ui-1.11.4.custom/jquery-ui.structure.min.css b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.structure.min.css
new file mode 100755
index 0000000..f5a4630
--- /dev/null
+++ b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.structure.min.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.11.4 - 2015-05-10
+* http://jqueryui.com
+* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;min-height:0;font-size:100%}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-button{display:inline-block;position:relative;padding:0;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:normal}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:none}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{position:relative;margin:0;padding:3px 1em 3px .4em;cursor:pointer;min-height:0;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-button{display:inline-block;overflow:hidden;position:relative;text-decoration:none;cursor:pointer}.ui-selectmenu-button span.ui-icon{right:0.5em;left:auto;margin-top:-8px;position:absolute;top:50%}.ui-selectmenu-button span.ui-selectmenu-text{text-align:left;padding:0.4em 2.1em 0.4em 1em;display:block;line-height:1.4;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}body .ui-tooltip{border-width:2px}
\ No newline at end of file
diff --git a/public/editor/jquery-ui-1.11.4.custom/jquery-ui.theme.css b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.theme.css
new file mode 100755
index 0000000..5db92db
--- /dev/null
+++ b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.theme.css
@@ -0,0 +1,410 @@
+/*!
+ * jQuery UI CSS Framework 1.11.4
+ * http://jqueryui.com
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/theming/
+ *
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
+ */
+
+
+/* Component containers
+----------------------------------*/
+.ui-widget {
+ font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;
+ font-size: 1.1em;
+}
+.ui-widget .ui-widget {
+ font-size: 1em;
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+ font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;
+ font-size: 1em;
+}
+.ui-widget-content {
+ border: 1px solid #dddddd;
+ background: #eeeeee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;
+ color: #333333;
+}
+.ui-widget-content a {
+ color: #333333;
+}
+.ui-widget-header {
+ border: 1px solid #e78f08;
+ background: #f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;
+ color: #ffffff;
+ font-weight: bold;
+}
+.ui-widget-header a {
+ color: #ffffff;
+}
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default {
+ border: 1px solid #cccccc;
+ background: #f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;
+ font-weight: bold;
+ color: #1c94c4;
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited {
+ color: #1c94c4;
+ text-decoration: none;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus {
+ border: 1px solid #fbcb09;
+ background: #fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;
+ font-weight: bold;
+ color: #c77405;
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited,
+.ui-state-focus a,
+.ui-state-focus a:hover,
+.ui-state-focus a:link,
+.ui-state-focus a:visited {
+ color: #c77405;
+ text-decoration: none;
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active {
+ border: 1px solid #fbd850;
+ background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
+ font-weight: bold;
+ color: #eb8f00;
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+ color: #eb8f00;
+ text-decoration: none;
+}
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+ border: 1px solid #fed22f;
+ background: #ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;
+ color: #363636;
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+ color: #363636;
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+ border: 1px solid #cd0a0a;
+ background: #b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;
+ color: #ffffff;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+ color: #ffffff;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+ color: #ffffff;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+ font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+ opacity: .7;
+ filter:Alpha(Opacity=70); /* support: IE8 */
+ font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+ opacity: .35;
+ filter:Alpha(Opacity=35); /* support: IE8 */
+ background-image: none;
+}
+.ui-state-disabled .ui-icon {
+ filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
+}
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+ width: 16px;
+ height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+ background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-widget-header .ui-icon {
+ background-image: url("images/ui-icons_ffffff_256x240.png");
+}
+.ui-state-default .ui-icon {
+ background-image: url("images/ui-icons_ef8c08_256x240.png");
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon {
+ background-image: url("images/ui-icons_ef8c08_256x240.png");
+}
+.ui-state-active .ui-icon {
+ background-image: url("images/ui-icons_ef8c08_256x240.png");
+}
+.ui-state-highlight .ui-icon {
+ background-image: url("images/ui-icons_228ef1_256x240.png");
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+ background-image: url("images/ui-icons_ffd27a_256x240.png");
+}
+
+/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+ border-top-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+ border-top-right-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+ border-bottom-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+ border-bottom-right-radius: 4px;
+}
+
+/* Overlays */
+.ui-widget-overlay {
+ background: #666666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;
+ opacity: .5;
+ filter: Alpha(Opacity=50); /* support: IE8 */
+}
+.ui-widget-shadow {
+ margin: -5px 0 0 -5px;
+ padding: 5px;
+ background: #000000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;
+ opacity: .2;
+ filter: Alpha(Opacity=20); /* support: IE8 */
+ border-radius: 5px;
+}
diff --git a/public/editor/jquery-ui-1.11.4.custom/jquery-ui.theme.min.css b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.theme.min.css
new file mode 100755
index 0000000..67b22a6
--- /dev/null
+++ b/public/editor/jquery-ui-1.11.4.custom/jquery-ui.theme.min.css
@@ -0,0 +1,5 @@
+/*! jQuery UI - v1.11.4 - 2015-05-10
+* http://jqueryui.com
+* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-widget{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Trebuchet MS,Tahoma,Verdana,Arial,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url("images/ui-bg_highlight-soft_100_eeeeee_1x100.png") 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #e78f08;background:#f6a828 url("images/ui-bg_gloss-wave_35_f6a828_500x100.png") 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url("images/ui-bg_glass_100_f6f6f6_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#1c94c4}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#1c94c4;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #fbcb09;background:#fdf5ce url("images/ui-bg_glass_100_fdf5ce_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#c77405}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited{color:#c77405;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #fbd850;background:#fff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;font-weight:bold;color:#eb8f00}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#eb8f00;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #fed22f;background:#ffe45c url("images/ui-bg_highlight-soft_75_ffe45c_1x100.png") 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url("images/ui-bg_diagonals-thick_18_b81900_40x40.png") 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_222222_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-default .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-active .ui-icon{background-image:url("images/ui-icons_ef8c08_256x240.png")}.ui-state-highlight .ui-icon{background-image:url("images/ui-icons_228ef1_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_ffd27a_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url("images/ui-bg_diagonals-thick_20_666666_40x40.png") 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url("images/ui-bg_flat_10_000000_40x100.png") 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);border-radius:5px}
\ No newline at end of file
diff --git a/public/editor/jquery.fileupload.js b/public/editor/jquery.fileupload.js
new file mode 100644
index 0000000..a45f18b
--- /dev/null
+++ b/public/editor/jquery.fileupload.js
@@ -0,0 +1,1467 @@
+/*
+ * jQuery File Upload Plugin 5.42.3
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2010, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/MIT
+ */
+
+/* jshint nomen:false */
+/* global define, require, window, document, location, Blob, FormData */
+
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // Register as an anonymous AMD module:
+ define([
+ 'jquery',
+ 'jquery.ui.widget'
+ ], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(
+ require('jquery'),
+ require('./vendor/jquery.ui.widget')
+ );
+ } else {
+ // Browser globals:
+ factory(window.jQuery);
+ }
+}(function ($) {
+ 'use strict';
+
+ // Detect file input support, based on
+ // http://viljamis.com/blog/2012/file-upload-support-on-mobile/
+ $.support.fileInput = !(new RegExp(
+ // Handle devices which give false positives for the feature detection:
+ '(Android (1\\.[0156]|2\\.[01]))' +
+ '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
+ '|(w(eb)?OSBrowser)|(webOS)' +
+ '|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
+ ).test(window.navigator.userAgent) ||
+ // Feature detection for all other devices:
+ $('
').prop('disabled'));
+
+ // The FileReader API is not actually used, but works as feature detection,
+ // as some Safari versions (5?) support XHR file uploads via the FormData API,
+ // but not non-multipart XHR file uploads.
+ // window.XMLHttpRequestUpload is not available on IE10, so we check for
+ // window.ProgressEvent instead to detect XHR2 file upload capability:
+ $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);
+ $.support.xhrFormDataFileUpload = !!window.FormData;
+
+ // Detect support for Blob slicing (required for chunked uploads):
+ $.support.blobSlice = window.Blob && (Blob.prototype.slice ||
+ Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
+
+ // Helper function to create drag handlers for dragover/dragenter/dragleave:
+ function getDragHandler(type) {
+ var isDragOver = type === 'dragover';
+ return function (e) {
+ e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
+ var dataTransfer = e.dataTransfer;
+ if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
+ this._trigger(
+ type,
+ $.Event(type, {delegatedEvent: e})
+ ) !== false) {
+ e.preventDefault();
+ if (isDragOver) {
+ dataTransfer.dropEffect = 'copy';
+ }
+ }
+ };
+ }
+
+ // The fileupload widget listens for change events on file input fields defined
+ // via fileInput setting and paste or drop events of the given dropZone.
+ // In addition to the default jQuery Widget methods, the fileupload widget
+ // exposes the "add" and "send" methods, to add or directly send files using
+ // the fileupload API.
+ // By default, files added via file input selection, paste, drag & drop or
+ // "add" method are uploaded immediately, but it is possible to override
+ // the "add" callback option to queue file uploads.
+ $.widget('blueimp.fileupload', {
+
+ options: {
+ // The drop target element(s), by the default the complete document.
+ // Set to null to disable drag & drop support:
+ dropZone: $(document),
+ // The paste target element(s), by the default undefined.
+ // Set to a DOM node or jQuery object to enable file pasting:
+ pasteZone: undefined,
+ // The file input field(s), that are listened to for change events.
+ // If undefined, it is set to the file input fields inside
+ // of the widget element on plugin initialization.
+ // Set to null to disable the change listener.
+ fileInput: undefined,
+ // By default, the file input field is replaced with a clone after
+ // each input field change event. This is required for iframe transport
+ // queues and allows change events to be fired for the same file
+ // selection, but can be disabled by setting the following option to false:
+ replaceFileInput: true,
+ // The parameter name for the file form data (the request argument name).
+ // If undefined or empty, the name property of the file input field is
+ // used, or "files[]" if the file input name property is also empty,
+ // can be a string or an array of strings:
+ paramName: undefined,
+ // By default, each file of a selection is uploaded using an individual
+ // request for XHR type uploads. Set to false to upload file
+ // selections in one request each:
+ singleFileUploads: true,
+ // To limit the number of files uploaded with one XHR request,
+ // set the following option to an integer greater than 0:
+ limitMultiFileUploads: undefined,
+ // The following option limits the number of files uploaded with one
+ // XHR request to keep the request size under or equal to the defined
+ // limit in bytes:
+ limitMultiFileUploadSize: undefined,
+ // Multipart file uploads add a number of bytes to each uploaded file,
+ // therefore the following option adds an overhead for each file used
+ // in the limitMultiFileUploadSize configuration:
+ limitMultiFileUploadSizeOverhead: 512,
+ // Set the following option to true to issue all file upload requests
+ // in a sequential order:
+ sequentialUploads: false,
+ // To limit the number of concurrent uploads,
+ // set the following option to an integer greater than 0:
+ limitConcurrentUploads: undefined,
+ // Set the following option to true to force iframe transport uploads:
+ forceIframeTransport: false,
+ // Set the following option to the location of a redirect url on the
+ // origin server, for cross-domain iframe transport uploads:
+ redirect: undefined,
+ // The parameter name for the redirect url, sent as part of the form
+ // data and set to 'redirect' if this option is empty:
+ redirectParamName: undefined,
+ // Set the following option to the location of a postMessage window,
+ // to enable postMessage transport uploads:
+ postMessage: undefined,
+ // By default, XHR file uploads are sent as multipart/form-data.
+ // The iframe transport is always using multipart/form-data.
+ // Set to false to enable non-multipart XHR uploads:
+ multipart: true,
+ // To upload large files in smaller chunks, set the following option
+ // to a preferred maximum chunk size. If set to 0, null or undefined,
+ // or the browser does not support the required Blob API, files will
+ // be uploaded as a whole.
+ maxChunkSize: undefined,
+ // When a non-multipart upload or a chunked multipart upload has been
+ // aborted, this option can be used to resume the upload by setting
+ // it to the size of the already uploaded bytes. This option is most
+ // useful when modifying the options object inside of the "add" or
+ // "send" callbacks, as the options are cloned for each file upload.
+ uploadedBytes: undefined,
+ // By default, failed (abort or error) file uploads are removed from the
+ // global progress calculation. Set the following option to false to
+ // prevent recalculating the global progress data:
+ recalculateProgress: true,
+ // Interval in milliseconds to calculate and trigger progress events:
+ progressInterval: 100,
+ // Interval in milliseconds to calculate progress bitrate:
+ bitrateInterval: 500,
+ // By default, uploads are started automatically when adding files:
+ autoUpload: true,
+
+ // Error and info messages:
+ messages: {
+ uploadedBytes: 'Uploaded bytes exceed file size'
+ },
+
+ // Translation function, gets the message key to be translated
+ // and an object with context specific data as arguments:
+ i18n: function (message, context) {
+ message = this.messages[message] || message.toString();
+ if (context) {
+ $.each(context, function (key, value) {
+ message = message.replace('{' + key + '}', value);
+ });
+ }
+ return message;
+ },
+
+ // Additional form data to be sent along with the file uploads can be set
+ // using this option, which accepts an array of objects with name and
+ // value properties, a function returning such an array, a FormData
+ // object (for XHR file uploads), or a simple object.
+ // The form of the first fileInput is given as parameter to the function:
+ formData: function (form) {
+ return form.serializeArray();
+ },
+
+ // The add callback is invoked as soon as files are added to the fileupload
+ // widget (via file input selection, drag & drop, paste or add API call).
+ // If the singleFileUploads option is enabled, this callback will be
+ // called once for each file in the selection for XHR file uploads, else
+ // once for each file selection.
+ //
+ // The upload starts when the submit method is invoked on the data parameter.
+ // The data object contains a files property holding the added files
+ // and allows you to override plugin options as well as define ajax settings.
+ //
+ // Listeners for this callback can also be bound the following way:
+ // .bind('fileuploadadd', func);
+ //
+ // data.submit() returns a Promise object and allows to attach additional
+ // handlers using jQuery's Deferred callbacks:
+ // data.submit().done(func).fail(func).always(func);
+ add: function (e, data) {
+ if (e.isDefaultPrevented()) {
+ return false;
+ }
+ if (data.autoUpload || (data.autoUpload !== false &&
+ $(this).fileupload('option', 'autoUpload'))) {
+ data.process().done(function () {
+ data.submit();
+ });
+ }
+ },
+
+ // Other callbacks:
+
+ // Callback for the submit event of each file upload:
+ // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
+
+ // Callback for the start of each file upload request:
+ // send: function (e, data) {}, // .bind('fileuploadsend', func);
+
+ // Callback for successful uploads:
+ // done: function (e, data) {}, // .bind('fileuploaddone', func);
+
+ // Callback for failed (abort or error) uploads:
+ // fail: function (e, data) {}, // .bind('fileuploadfail', func);
+
+ // Callback for completed (success, abort or error) requests:
+ // always: function (e, data) {}, // .bind('fileuploadalways', func);
+
+ // Callback for upload progress events:
+ // progress: function (e, data) {}, // .bind('fileuploadprogress', func);
+
+ // Callback for global upload progress events:
+ // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
+
+ // Callback for uploads start, equivalent to the global ajaxStart event:
+ // start: function (e) {}, // .bind('fileuploadstart', func);
+
+ // Callback for uploads stop, equivalent to the global ajaxStop event:
+ // stop: function (e) {}, // .bind('fileuploadstop', func);
+
+ // Callback for change events of the fileInput(s):
+ // change: function (e, data) {}, // .bind('fileuploadchange', func);
+
+ // Callback for paste events to the pasteZone(s):
+ // paste: function (e, data) {}, // .bind('fileuploadpaste', func);
+
+ // Callback for drop events of the dropZone(s):
+ // drop: function (e, data) {}, // .bind('fileuploaddrop', func);
+
+ // Callback for dragover events of the dropZone(s):
+ // dragover: function (e) {}, // .bind('fileuploaddragover', func);
+
+ // Callback for the start of each chunk upload request:
+ // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
+
+ // Callback for successful chunk uploads:
+ // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
+
+ // Callback for failed (abort or error) chunk uploads:
+ // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
+
+ // Callback for completed (success, abort or error) chunk upload requests:
+ // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
+
+ // The plugin options are used as settings object for the ajax calls.
+ // The following are jQuery ajax settings required for the file uploads:
+ processData: false,
+ contentType: false,
+ cache: false
+ },
+
+ // A list of options that require reinitializing event listeners and/or
+ // special initialization code:
+ _specialOptions: [
+ 'fileInput',
+ 'dropZone',
+ 'pasteZone',
+ 'multipart',
+ 'forceIframeTransport'
+ ],
+
+ _blobSlice: $.support.blobSlice && function () {
+ var slice = this.slice || this.webkitSlice || this.mozSlice;
+ return slice.apply(this, arguments);
+ },
+
+ _BitrateTimer: function () {
+ this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
+ this.loaded = 0;
+ this.bitrate = 0;
+ this.getBitrate = function (now, loaded, interval) {
+ var timeDiff = now - this.timestamp;
+ if (!this.bitrate || !interval || timeDiff > interval) {
+ this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
+ this.loaded = loaded;
+ this.timestamp = now;
+ }
+ return this.bitrate;
+ };
+ },
+
+ _isXHRUpload: function (options) {
+ return !options.forceIframeTransport &&
+ ((!options.multipart && $.support.xhrFileUpload) ||
+ $.support.xhrFormDataFileUpload);
+ },
+
+ _getFormData: function (options) {
+ var formData;
+ if ($.type(options.formData) === 'function') {
+ return options.formData(options.form);
+ }
+ if ($.isArray(options.formData)) {
+ return options.formData;
+ }
+ if ($.type(options.formData) === 'object') {
+ formData = [];
+ $.each(options.formData, function (name, value) {
+ formData.push({name: name, value: value});
+ });
+ return formData;
+ }
+ return [];
+ },
+
+ _getTotal: function (files) {
+ var total = 0;
+ $.each(files, function (index, file) {
+ total += file.size || 1;
+ });
+ return total;
+ },
+
+ _initProgressObject: function (obj) {
+ var progress = {
+ loaded: 0,
+ total: 0,
+ bitrate: 0
+ };
+ if (obj._progress) {
+ $.extend(obj._progress, progress);
+ } else {
+ obj._progress = progress;
+ }
+ },
+
+ _initResponseObject: function (obj) {
+ var prop;
+ if (obj._response) {
+ for (prop in obj._response) {
+ if (obj._response.hasOwnProperty(prop)) {
+ delete obj._response[prop];
+ }
+ }
+ } else {
+ obj._response = {};
+ }
+ },
+
+ _onProgress: function (e, data) {
+ if (e.lengthComputable) {
+ var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
+ loaded;
+ if (data._time && data.progressInterval &&
+ (now - data._time < data.progressInterval) &&
+ e.loaded !== e.total) {
+ return;
+ }
+ data._time = now;
+ loaded = Math.floor(
+ e.loaded / e.total * (data.chunkSize || data._progress.total)
+ ) + (data.uploadedBytes || 0);
+ // Add the difference from the previously loaded state
+ // to the global loaded counter:
+ this._progress.loaded += (loaded - data._progress.loaded);
+ this._progress.bitrate = this._bitrateTimer.getBitrate(
+ now,
+ this._progress.loaded,
+ data.bitrateInterval
+ );
+ data._progress.loaded = data.loaded = loaded;
+ data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
+ now,
+ loaded,
+ data.bitrateInterval
+ );
+ // Trigger a custom progress event with a total data property set
+ // to the file size(s) of the current upload and a loaded data
+ // property calculated accordingly:
+ this._trigger(
+ 'progress',
+ $.Event('progress', {delegatedEvent: e}),
+ data
+ );
+ // Trigger a global progress event for all current file uploads,
+ // including ajax calls queued for sequential file uploads:
+ this._trigger(
+ 'progressall',
+ $.Event('progressall', {delegatedEvent: e}),
+ this._progress
+ );
+ }
+ },
+
+ _initProgressListener: function (options) {
+ var that = this,
+ xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
+ // Accesss to the native XHR object is required to add event listeners
+ // for the upload progress event:
+ if (xhr.upload) {
+ $(xhr.upload).bind('progress', function (e) {
+ var oe = e.originalEvent;
+ // Make sure the progress event properties get copied over:
+ e.lengthComputable = oe.lengthComputable;
+ e.loaded = oe.loaded;
+ e.total = oe.total;
+ that._onProgress(e, options);
+ });
+ options.xhr = function () {
+ return xhr;
+ };
+ }
+ },
+
+ _isInstanceOf: function (type, obj) {
+ // Cross-frame instanceof check
+ return Object.prototype.toString.call(obj) === '[object ' + type + ']';
+ },
+
+ _initXHRData: function (options) {
+ var that = this,
+ formData,
+ file = options.files[0],
+ // Ignore non-multipart setting if not supported:
+ multipart = options.multipart || !$.support.xhrFileUpload,
+ paramName = $.type(options.paramName) === 'array' ?
+ options.paramName[0] : options.paramName;
+ options.headers = $.extend({}, options.headers);
+ if (options.contentRange) {
+ options.headers['Content-Range'] = options.contentRange;
+ }
+ if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
+ options.headers['Content-Disposition'] = 'attachment; filename="' +
+ encodeURI(file.name) + '"';
+ }
+ if (!multipart) {
+ options.contentType = file.type || 'application/octet-stream';
+ options.data = options.blob || file;
+ } else if ($.support.xhrFormDataFileUpload) {
+ if (options.postMessage) {
+ // window.postMessage does not allow sending FormData
+ // objects, so we just add the File/Blob objects to
+ // the formData array and let the postMessage window
+ // create the FormData object out of this array:
+ formData = this._getFormData(options);
+ if (options.blob) {
+ formData.push({
+ name: paramName,
+ value: options.blob
+ });
+ } else {
+ $.each(options.files, function (index, file) {
+ formData.push({
+ name: ($.type(options.paramName) === 'array' &&
+ options.paramName[index]) || paramName,
+ value: file
+ });
+ });
+ }
+ } else {
+ if (that._isInstanceOf('FormData', options.formData)) {
+ formData = options.formData;
+ } else {
+ formData = new FormData();
+ $.each(this._getFormData(options), function (index, field) {
+ formData.append(field.name, field.value);
+ });
+ }
+ if (options.blob) {
+ formData.append(paramName, options.blob, file.name);
+ } else {
+ $.each(options.files, function (index, file) {
+ // This check allows the tests to run with
+ // dummy objects:
+ if (that._isInstanceOf('File', file) ||
+ that._isInstanceOf('Blob', file)) {
+ formData.append(
+ ($.type(options.paramName) === 'array' &&
+ options.paramName[index]) || paramName,
+ file,
+ file.uploadName || file.name
+ );
+ }
+ });
+ }
+ }
+ options.data = formData;
+ }
+ // Blob reference is not needed anymore, free memory:
+ options.blob = null;
+ },
+
+ _initIframeSettings: function (options) {
+ var targetHost = $('
').prop('href', options.url).prop('host');
+ // Setting the dataType to iframe enables the iframe transport:
+ options.dataType = 'iframe ' + (options.dataType || '');
+ // The iframe transport accepts a serialized array as form data:
+ options.formData = this._getFormData(options);
+ // Add redirect url to form data on cross-domain uploads:
+ if (options.redirect && targetHost && targetHost !== location.host) {
+ options.formData.push({
+ name: options.redirectParamName || 'redirect',
+ value: options.redirect
+ });
+ }
+ },
+
+ _initDataSettings: function (options) {
+ if (this._isXHRUpload(options)) {
+ if (!this._chunkedUpload(options, true)) {
+ if (!options.data) {
+ this._initXHRData(options);
+ }
+ this._initProgressListener(options);
+ }
+ if (options.postMessage) {
+ // Setting the dataType to postmessage enables the
+ // postMessage transport:
+ options.dataType = 'postmessage ' + (options.dataType || '');
+ }
+ } else {
+ this._initIframeSettings(options);
+ }
+ },
+
+ _getParamName: function (options) {
+ var fileInput = $(options.fileInput),
+ paramName = options.paramName;
+ if (!paramName) {
+ paramName = [];
+ fileInput.each(function () {
+ var input = $(this),
+ name = input.prop('name') || 'files[]',
+ i = (input.prop('files') || [1]).length;
+ while (i) {
+ paramName.push(name);
+ i -= 1;
+ }
+ });
+ if (!paramName.length) {
+ paramName = [fileInput.prop('name') || 'files[]'];
+ }
+ } else if (!$.isArray(paramName)) {
+ paramName = [paramName];
+ }
+ return paramName;
+ },
+
+ _initFormSettings: function (options) {
+ // Retrieve missing options from the input field and the
+ // associated form, if available:
+ if (!options.form || !options.form.length) {
+ options.form = $(options.fileInput.prop('form'));
+ // If the given file input doesn't have an associated form,
+ // use the default widget file input's form:
+ if (!options.form.length) {
+ options.form = $(this.options.fileInput.prop('form'));
+ }
+ }
+ options.paramName = this._getParamName(options);
+ if (!options.url) {
+ options.url = options.form.prop('action') || location.href;
+ }
+ // The HTTP request method must be "POST" or "PUT":
+ options.type = (options.type ||
+ ($.type(options.form.prop('method')) === 'string' &&
+ options.form.prop('method')) || ''
+ ).toUpperCase();
+ if (options.type !== 'POST' && options.type !== 'PUT' &&
+ options.type !== 'PATCH') {
+ options.type = 'POST';
+ }
+ if (!options.formAcceptCharset) {
+ options.formAcceptCharset = options.form.attr('accept-charset');
+ }
+ },
+
+ _getAJAXSettings: function (data) {
+ var options = $.extend({}, this.options, data);
+ this._initFormSettings(options);
+ this._initDataSettings(options);
+ return options;
+ },
+
+ // jQuery 1.6 doesn't provide .state(),
+ // while jQuery 1.8+ removed .isRejected() and .isResolved():
+ _getDeferredState: function (deferred) {
+ if (deferred.state) {
+ return deferred.state();
+ }
+ if (deferred.isResolved()) {
+ return 'resolved';
+ }
+ if (deferred.isRejected()) {
+ return 'rejected';
+ }
+ return 'pending';
+ },
+
+ // Maps jqXHR callbacks to the equivalent
+ // methods of the given Promise object:
+ _enhancePromise: function (promise) {
+ promise.success = promise.done;
+ promise.error = promise.fail;
+ promise.complete = promise.always;
+ return promise;
+ },
+
+ // Creates and returns a Promise object enhanced with
+ // the jqXHR methods abort, success, error and complete:
+ _getXHRPromise: function (resolveOrReject, context, args) {
+ var dfd = $.Deferred(),
+ promise = dfd.promise();
+ context = context || this.options.context || promise;
+ if (resolveOrReject === true) {
+ dfd.resolveWith(context, args);
+ } else if (resolveOrReject === false) {
+ dfd.rejectWith(context, args);
+ }
+ promise.abort = dfd.promise;
+ return this._enhancePromise(promise);
+ },
+
+ // Adds convenience methods to the data callback argument:
+ _addConvenienceMethods: function (e, data) {
+ var that = this,
+ getPromise = function (args) {
+ return $.Deferred().resolveWith(that, args).promise();
+ };
+ data.process = function (resolveFunc, rejectFunc) {
+ if (resolveFunc || rejectFunc) {
+ data._processQueue = this._processQueue =
+ (this._processQueue || getPromise([this])).pipe(
+ function () {
+ if (data.errorThrown) {
+ return $.Deferred()
+ .rejectWith(that, [data]).promise();
+ }
+ return getPromise(arguments);
+ }
+ ).pipe(resolveFunc, rejectFunc);
+ }
+ return this._processQueue || getPromise([this]);
+ };
+ data.submit = function () {
+ if (this.state() !== 'pending') {
+ data.jqXHR = this.jqXHR =
+ (that._trigger(
+ 'submit',
+ $.Event('submit', {delegatedEvent: e}),
+ this
+ ) !== false) && that._onSend(e, this);
+ }
+ return this.jqXHR || that._getXHRPromise();
+ };
+ data.abort = function () {
+ if (this.jqXHR) {
+ return this.jqXHR.abort();
+ }
+ this.errorThrown = 'abort';
+ that._trigger('fail', null, this);
+ return that._getXHRPromise(false);
+ };
+ data.state = function () {
+ if (this.jqXHR) {
+ return that._getDeferredState(this.jqXHR);
+ }
+ if (this._processQueue) {
+ return that._getDeferredState(this._processQueue);
+ }
+ };
+ data.processing = function () {
+ return !this.jqXHR && this._processQueue && that
+ ._getDeferredState(this._processQueue) === 'pending';
+ };
+ data.progress = function () {
+ return this._progress;
+ };
+ data.response = function () {
+ return this._response;
+ };
+ },
+
+ // Parses the Range header from the server response
+ // and returns the uploaded bytes:
+ _getUploadedBytes: function (jqXHR) {
+ var range = jqXHR.getResponseHeader('Range'),
+ parts = range && range.split('-'),
+ upperBytesPos = parts && parts.length > 1 &&
+ parseInt(parts[1], 10);
+ return upperBytesPos && upperBytesPos + 1;
+ },
+
+ // Uploads a file in multiple, sequential requests
+ // by splitting the file up in multiple blob chunks.
+ // If the second parameter is true, only tests if the file
+ // should be uploaded in chunks, but does not invoke any
+ // upload requests:
+ _chunkedUpload: function (options, testOnly) {
+ options.uploadedBytes = options.uploadedBytes || 0;
+ var that = this,
+ file = options.files[0],
+ fs = file.size,
+ ub = options.uploadedBytes,
+ mcs = options.maxChunkSize || fs,
+ slice = this._blobSlice,
+ dfd = $.Deferred(),
+ promise = dfd.promise(),
+ jqXHR,
+ upload;
+ if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) ||
+ options.data) {
+ return false;
+ }
+ if (testOnly) {
+ return true;
+ }
+ if (ub >= fs) {
+ file.error = options.i18n('uploadedBytes');
+ return this._getXHRPromise(
+ false,
+ options.context,
+ [null, 'error', file.error]
+ );
+ }
+ // The chunk upload method:
+ upload = function () {
+ // Clone the options object for each chunk upload:
+ var o = $.extend({}, options),
+ currentLoaded = o._progress.loaded;
+ o.blob = slice.call(
+ file,
+ ub,
+ ub + mcs,
+ file.type
+ );
+ // Store the current chunk size, as the blob itself
+ // will be dereferenced after data processing:
+ o.chunkSize = o.blob.size;
+ // Expose the chunk bytes position range:
+ o.contentRange = 'bytes ' + ub + '-' +
+ (ub + o.chunkSize - 1) + '/' + fs;
+ // Process the upload data (the blob and potential form data):
+ that._initXHRData(o);
+ // Add progress listeners for this chunk upload:
+ that._initProgressListener(o);
+ jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||
+ that._getXHRPromise(false, o.context))
+ .done(function (result, textStatus, jqXHR) {
+ ub = that._getUploadedBytes(jqXHR) ||
+ (ub + o.chunkSize);
+ // Create a progress event if no final progress event
+ // with loaded equaling total has been triggered
+ // for this chunk:
+ if (currentLoaded + o.chunkSize - o._progress.loaded) {
+ that._onProgress($.Event('progress', {
+ lengthComputable: true,
+ loaded: ub - o.uploadedBytes,
+ total: ub - o.uploadedBytes
+ }), o);
+ }
+ options.uploadedBytes = o.uploadedBytes = ub;
+ o.result = result;
+ o.textStatus = textStatus;
+ o.jqXHR = jqXHR;
+ that._trigger('chunkdone', null, o);
+ that._trigger('chunkalways', null, o);
+ if (ub < fs) {
+ // File upload not yet complete,
+ // continue with the next chunk:
+ upload();
+ } else {
+ dfd.resolveWith(
+ o.context,
+ [result, textStatus, jqXHR]
+ );
+ }
+ })
+ .fail(function (jqXHR, textStatus, errorThrown) {
+ o.jqXHR = jqXHR;
+ o.textStatus = textStatus;
+ o.errorThrown = errorThrown;
+ that._trigger('chunkfail', null, o);
+ that._trigger('chunkalways', null, o);
+ dfd.rejectWith(
+ o.context,
+ [jqXHR, textStatus, errorThrown]
+ );
+ });
+ };
+ this._enhancePromise(promise);
+ promise.abort = function () {
+ return jqXHR.abort();
+ };
+ upload();
+ return promise;
+ },
+
+ _beforeSend: function (e, data) {
+ if (this._active === 0) {
+ // the start callback is triggered when an upload starts
+ // and no other uploads are currently running,
+ // equivalent to the global ajaxStart event:
+ this._trigger('start');
+ // Set timer for global bitrate progress calculation:
+ this._bitrateTimer = new this._BitrateTimer();
+ // Reset the global progress values:
+ this._progress.loaded = this._progress.total = 0;
+ this._progress.bitrate = 0;
+ }
+ // Make sure the container objects for the .response() and
+ // .progress() methods on the data object are available
+ // and reset to their initial state:
+ this._initResponseObject(data);
+ this._initProgressObject(data);
+ data._progress.loaded = data.loaded = data.uploadedBytes || 0;
+ data._progress.total = data.total = this._getTotal(data.files) || 1;
+ data._progress.bitrate = data.bitrate = 0;
+ this._active += 1;
+ // Initialize the global progress values:
+ this._progress.loaded += data.loaded;
+ this._progress.total += data.total;
+ },
+
+ _onDone: function (result, textStatus, jqXHR, options) {
+ var total = options._progress.total,
+ response = options._response;
+ if (options._progress.loaded < total) {
+ // Create a progress event if no final progress event
+ // with loaded equaling total has been triggered:
+ this._onProgress($.Event('progress', {
+ lengthComputable: true,
+ loaded: total,
+ total: total
+ }), options);
+ }
+ response.result = options.result = result;
+ response.textStatus = options.textStatus = textStatus;
+ response.jqXHR = options.jqXHR = jqXHR;
+ this._trigger('done', null, options);
+ },
+
+ _onFail: function (jqXHR, textStatus, errorThrown, options) {
+ var response = options._response;
+ if (options.recalculateProgress) {
+ // Remove the failed (error or abort) file upload from
+ // the global progress calculation:
+ this._progress.loaded -= options._progress.loaded;
+ this._progress.total -= options._progress.total;
+ }
+ response.jqXHR = options.jqXHR = jqXHR;
+ response.textStatus = options.textStatus = textStatus;
+ response.errorThrown = options.errorThrown = errorThrown;
+ this._trigger('fail', null, options);
+ },
+
+ _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
+ // jqXHRorResult, textStatus and jqXHRorError are added to the
+ // options object via done and fail callbacks
+ this._trigger('always', null, options);
+ },
+
+ _onSend: function (e, data) {
+ if (!data.submit) {
+ this._addConvenienceMethods(e, data);
+ }
+ var that = this,
+ jqXHR,
+ aborted,
+ slot,
+ pipe,
+ options = that._getAJAXSettings(data),
+ send = function () {
+ that._sending += 1;
+ // Set timer for bitrate progress calculation:
+ options._bitrateTimer = new that._BitrateTimer();
+ jqXHR = jqXHR || (
+ ((aborted || that._trigger(
+ 'send',
+ $.Event('send', {delegatedEvent: e}),
+ options
+ ) === false) &&
+ that._getXHRPromise(false, options.context, aborted)) ||
+ that._chunkedUpload(options) || $.ajax(options)
+ ).done(function (result, textStatus, jqXHR) {
+ that._onDone(result, textStatus, jqXHR, options);
+ }).fail(function (jqXHR, textStatus, errorThrown) {
+ that._onFail(jqXHR, textStatus, errorThrown, options);
+ }).always(function (jqXHRorResult, textStatus, jqXHRorError) {
+ that._onAlways(
+ jqXHRorResult,
+ textStatus,
+ jqXHRorError,
+ options
+ );
+ that._sending -= 1;
+ that._active -= 1;
+ if (options.limitConcurrentUploads &&
+ options.limitConcurrentUploads > that._sending) {
+ // Start the next queued upload,
+ // that has not been aborted:
+ var nextSlot = that._slots.shift();
+ while (nextSlot) {
+ if (that._getDeferredState(nextSlot) === 'pending') {
+ nextSlot.resolve();
+ break;
+ }
+ nextSlot = that._slots.shift();
+ }
+ }
+ if (that._active === 0) {
+ // The stop callback is triggered when all uploads have
+ // been completed, equivalent to the global ajaxStop event:
+ that._trigger('stop');
+ }
+ });
+ return jqXHR;
+ };
+ this._beforeSend(e, options);
+ if (this.options.sequentialUploads ||
+ (this.options.limitConcurrentUploads &&
+ this.options.limitConcurrentUploads <= this._sending)) {
+ if (this.options.limitConcurrentUploads > 1) {
+ slot = $.Deferred();
+ this._slots.push(slot);
+ pipe = slot.pipe(send);
+ } else {
+ this._sequence = this._sequence.pipe(send, send);
+ pipe = this._sequence;
+ }
+ // Return the piped Promise object, enhanced with an abort method,
+ // which is delegated to the jqXHR object of the current upload,
+ // and jqXHR callbacks mapped to the equivalent Promise methods:
+ pipe.abort = function () {
+ aborted = [undefined, 'abort', 'abort'];
+ if (!jqXHR) {
+ if (slot) {
+ slot.rejectWith(options.context, aborted);
+ }
+ return send();
+ }
+ return jqXHR.abort();
+ };
+ return this._enhancePromise(pipe);
+ }
+ return send();
+ },
+
+ _onAdd: function (e, data) {
+ var that = this,
+ result = true,
+ options = $.extend({}, this.options, data),
+ files = data.files,
+ filesLength = files.length,
+ limit = options.limitMultiFileUploads,
+ limitSize = options.limitMultiFileUploadSize,
+ overhead = options.limitMultiFileUploadSizeOverhead,
+ batchSize = 0,
+ paramName = this._getParamName(options),
+ paramNameSet,
+ paramNameSlice,
+ fileSet,
+ i,
+ j = 0;
+ if (limitSize && (!filesLength || files[0].size === undefined)) {
+ limitSize = undefined;
+ }
+ if (!(options.singleFileUploads || limit || limitSize) ||
+ !this._isXHRUpload(options)) {
+ fileSet = [files];
+ paramNameSet = [paramName];
+ } else if (!(options.singleFileUploads || limitSize) && limit) {
+ fileSet = [];
+ paramNameSet = [];
+ for (i = 0; i < filesLength; i += limit) {
+ fileSet.push(files.slice(i, i + limit));
+ paramNameSlice = paramName.slice(i, i + limit);
+ if (!paramNameSlice.length) {
+ paramNameSlice = paramName;
+ }
+ paramNameSet.push(paramNameSlice);
+ }
+ } else if (!options.singleFileUploads && limitSize) {
+ fileSet = [];
+ paramNameSet = [];
+ for (i = 0; i < filesLength; i = i + 1) {
+ batchSize += files[i].size + overhead;
+ if (i + 1 === filesLength ||
+ ((batchSize + files[i + 1].size + overhead) > limitSize) ||
+ (limit && i + 1 - j >= limit)) {
+ fileSet.push(files.slice(j, i + 1));
+ paramNameSlice = paramName.slice(j, i + 1);
+ if (!paramNameSlice.length) {
+ paramNameSlice = paramName;
+ }
+ paramNameSet.push(paramNameSlice);
+ j = i + 1;
+ batchSize = 0;
+ }
+ }
+ } else {
+ paramNameSet = paramName;
+ }
+ data.originalFiles = files;
+ $.each(fileSet || files, function (index, element) {
+ var newData = $.extend({}, data);
+ newData.files = fileSet ? element : [element];
+ newData.paramName = paramNameSet[index];
+ that._initResponseObject(newData);
+ that._initProgressObject(newData);
+ that._addConvenienceMethods(e, newData);
+ result = that._trigger(
+ 'add',
+ $.Event('add', {delegatedEvent: e}),
+ newData
+ );
+ return result;
+ });
+ return result;
+ },
+
+ _replaceFileInput: function (data) {
+ var input = data.fileInput,
+ inputClone = input.clone(true);
+ // Add a reference for the new cloned file input to the data argument:
+ data.fileInputClone = inputClone;
+ $('
').append(inputClone)[0].reset();
+ // Detaching allows to insert the fileInput on another form
+ // without loosing the file input value:
+ input.after(inputClone).detach();
+ // Avoid memory leaks with the detached file input:
+ $.cleanData(input.unbind('remove'));
+ // Replace the original file input element in the fileInput
+ // elements set with the clone, which has been copied including
+ // event handlers:
+ this.options.fileInput = this.options.fileInput.map(function (i, el) {
+ if (el === input[0]) {
+ return inputClone[0];
+ }
+ return el;
+ });
+ // If the widget has been initialized on the file input itself,
+ // override this.element with the file input clone:
+ if (input[0] === this.element[0]) {
+ this.element = inputClone;
+ }
+ },
+
+ _handleFileTreeEntry: function (entry, path) {
+ var that = this,
+ dfd = $.Deferred(),
+ errorHandler = function (e) {
+ if (e && !e.entry) {
+ e.entry = entry;
+ }
+ // Since $.when returns immediately if one
+ // Deferred is rejected, we use resolve instead.
+ // This allows valid files and invalid items
+ // to be returned together in one set:
+ dfd.resolve([e]);
+ },
+ successHandler = function (entries) {
+ that._handleFileTreeEntries(
+ entries,
+ path + entry.name + '/'
+ ).done(function (files) {
+ dfd.resolve(files);
+ }).fail(errorHandler);
+ },
+ readEntries = function () {
+ dirReader.readEntries(function (results) {
+ if (!results.length) {
+ successHandler(entries);
+ } else {
+ entries = entries.concat(results);
+ readEntries();
+ }
+ }, errorHandler);
+ },
+ dirReader, entries = [];
+ path = path || '';
+ if (entry.isFile) {
+ if (entry._file) {
+ // Workaround for Chrome bug #149735
+ entry._file.relativePath = path;
+ dfd.resolve(entry._file);
+ } else {
+ entry.file(function (file) {
+ file.relativePath = path;
+ dfd.resolve(file);
+ }, errorHandler);
+ }
+ } else if (entry.isDirectory) {
+ dirReader = entry.createReader();
+ readEntries();
+ } else {
+ // Return an empy list for file system items
+ // other than files or directories:
+ dfd.resolve([]);
+ }
+ return dfd.promise();
+ },
+
+ _handleFileTreeEntries: function (entries, path) {
+ var that = this;
+ return $.when.apply(
+ $,
+ $.map(entries, function (entry) {
+ return that._handleFileTreeEntry(entry, path);
+ })
+ ).pipe(function () {
+ return Array.prototype.concat.apply(
+ [],
+ arguments
+ );
+ });
+ },
+
+ _getDroppedFiles: function (dataTransfer) {
+ dataTransfer = dataTransfer || {};
+ var items = dataTransfer.items;
+ if (items && items.length && (items[0].webkitGetAsEntry ||
+ items[0].getAsEntry)) {
+ return this._handleFileTreeEntries(
+ $.map(items, function (item) {
+ var entry;
+ if (item.webkitGetAsEntry) {
+ entry = item.webkitGetAsEntry();
+ if (entry) {
+ // Workaround for Chrome bug #149735:
+ entry._file = item.getAsFile();
+ }
+ return entry;
+ }
+ return item.getAsEntry();
+ })
+ );
+ }
+ return $.Deferred().resolve(
+ $.makeArray(dataTransfer.files)
+ ).promise();
+ },
+
+ _getSingleFileInputFiles: function (fileInput) {
+ fileInput = $(fileInput);
+ var entries = fileInput.prop('webkitEntries') ||
+ fileInput.prop('entries'),
+ files,
+ value;
+ if (entries && entries.length) {
+ return this._handleFileTreeEntries(entries);
+ }
+ files = $.makeArray(fileInput.prop('files'));
+ if (!files.length) {
+ value = fileInput.prop('value');
+ if (!value) {
+ return $.Deferred().resolve([]).promise();
+ }
+ // If the files property is not available, the browser does not
+ // support the File API and we add a pseudo File object with
+ // the input value as name with path information removed:
+ files = [{name: value.replace(/^.*\\/, '')}];
+ } else if (files[0].name === undefined && files[0].fileName) {
+ // File normalization for Safari 4 and Firefox 3:
+ $.each(files, function (index, file) {
+ file.name = file.fileName;
+ file.size = file.fileSize;
+ });
+ }
+ return $.Deferred().resolve(files).promise();
+ },
+
+ _getFileInputFiles: function (fileInput) {
+ if (!(fileInput instanceof $) || fileInput.length === 1) {
+ return this._getSingleFileInputFiles(fileInput);
+ }
+ return $.when.apply(
+ $,
+ $.map(fileInput, this._getSingleFileInputFiles)
+ ).pipe(function () {
+ return Array.prototype.concat.apply(
+ [],
+ arguments
+ );
+ });
+ },
+
+ _onChange: function (e) {
+ var that = this,
+ data = {
+ fileInput: $(e.target),
+ form: $(e.target.form)
+ };
+ this._getFileInputFiles(data.fileInput).always(function (files) {
+ data.files = files;
+ if (that.options.replaceFileInput) {
+ that._replaceFileInput(data);
+ }
+ if (that._trigger(
+ 'change',
+ $.Event('change', {delegatedEvent: e}),
+ data
+ ) !== false) {
+ that._onAdd(e, data);
+ }
+ });
+ },
+
+ _onPaste: function (e) {
+ var items = e.originalEvent && e.originalEvent.clipboardData &&
+ e.originalEvent.clipboardData.items,
+ data = {files: []};
+ if (items && items.length) {
+ $.each(items, function (index, item) {
+ var file = item.getAsFile && item.getAsFile();
+ if (file) {
+ data.files.push(file);
+ }
+ });
+ if (this._trigger(
+ 'paste',
+ $.Event('paste', {delegatedEvent: e}),
+ data
+ ) !== false) {
+ this._onAdd(e, data);
+ }
+ }
+ },
+
+ _onDrop: function (e) {
+ e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
+ var that = this,
+ dataTransfer = e.dataTransfer,
+ data = {};
+ if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
+ e.preventDefault();
+ this._getDroppedFiles(dataTransfer).always(function (files) {
+ data.files = files;
+ if (that._trigger(
+ 'drop',
+ $.Event('drop', {delegatedEvent: e}),
+ data
+ ) !== false) {
+ that._onAdd(e, data);
+ }
+ });
+ }
+ },
+
+ _onDragOver: getDragHandler('dragover'),
+
+ _onDragEnter: getDragHandler('dragenter'),
+
+ _onDragLeave: getDragHandler('dragleave'),
+
+ _initEventHandlers: function () {
+ if (this._isXHRUpload(this.options)) {
+ this._on(this.options.dropZone, {
+ dragover: this._onDragOver,
+ drop: this._onDrop,
+ // event.preventDefault() on dragenter is required for IE10+:
+ dragenter: this._onDragEnter,
+ // dragleave is not required, but added for completeness:
+ dragleave: this._onDragLeave
+ });
+ this._on(this.options.pasteZone, {
+ paste: this._onPaste
+ });
+ }
+ if ($.support.fileInput) {
+ this._on(this.options.fileInput, {
+ change: this._onChange
+ });
+ }
+ },
+
+ _destroyEventHandlers: function () {
+ this._off(this.options.dropZone, 'dragenter dragleave dragover drop');
+ this._off(this.options.pasteZone, 'paste');
+ this._off(this.options.fileInput, 'change');
+ },
+
+ _setOption: function (key, value) {
+ var reinit = $.inArray(key, this._specialOptions) !== -1;
+ if (reinit) {
+ this._destroyEventHandlers();
+ }
+ this._super(key, value);
+ if (reinit) {
+ this._initSpecialOptions();
+ this._initEventHandlers();
+ }
+ },
+
+ _initSpecialOptions: function () {
+ var options = this.options;
+ if (options.fileInput === undefined) {
+ options.fileInput = this.element.is('input[type="file"]') ?
+ this.element : this.element.find('input[type="file"]');
+ } else if (!(options.fileInput instanceof $)) {
+ options.fileInput = $(options.fileInput);
+ }
+ if (!(options.dropZone instanceof $)) {
+ options.dropZone = $(options.dropZone);
+ }
+ if (!(options.pasteZone instanceof $)) {
+ options.pasteZone = $(options.pasteZone);
+ }
+ },
+
+ _getRegExp: function (str) {
+ var parts = str.split('/'),
+ modifiers = parts.pop();
+ parts.shift();
+ return new RegExp(parts.join('/'), modifiers);
+ },
+
+ _isRegExpOption: function (key, value) {
+ return key !== 'url' && $.type(value) === 'string' &&
+ /^\/.*\/[igm]{0,3}$/.test(value);
+ },
+
+ _initDataAttributes: function () {
+ var that = this,
+ options = this.options,
+ data = this.element.data();
+ // Initialize options set via HTML5 data-attributes:
+ $.each(
+ this.element[0].attributes,
+ function (index, attr) {
+ var key = attr.name.toLowerCase(),
+ value;
+ if (/^data-/.test(key)) {
+ // Convert hyphen-ated key to camelCase:
+ key = key.slice(5).replace(/-[a-z]/g, function (str) {
+ return str.charAt(1).toUpperCase();
+ });
+ value = data[key];
+ if (that._isRegExpOption(key, value)) {
+ value = that._getRegExp(value);
+ }
+ options[key] = value;
+ }
+ }
+ );
+ },
+
+ _create: function () {
+ this._initDataAttributes();
+ this._initSpecialOptions();
+ this._slots = [];
+ this._sequence = this._getXHRPromise(true);
+ this._sending = this._active = 0;
+ this._initProgressObject(this);
+ this._initEventHandlers();
+ },
+
+ // This method is exposed to the widget API and allows to query
+ // the number of active uploads:
+ active: function () {
+ return this._active;
+ },
+
+ // This method is exposed to the widget API and allows to query
+ // the widget upload progress.
+ // It returns an object with loaded, total and bitrate properties
+ // for the running uploads:
+ progress: function () {
+ return this._progress;
+ },
+
+ // This method is exposed to the widget API and allows adding files
+ // using the fileupload API. The data parameter accepts an object which
+ // must have a files property and can contain additional options:
+ // .fileupload('add', {files: filesList});
+ add: function (data) {
+ var that = this;
+ if (!data || this.options.disabled) {
+ return;
+ }
+ if (data.fileInput && !data.files) {
+ this._getFileInputFiles(data.fileInput).always(function (files) {
+ data.files = files;
+ that._onAdd(null, data);
+ });
+ } else {
+ data.files = $.makeArray(data.files);
+ this._onAdd(null, data);
+ }
+ },
+
+ // This method is exposed to the widget API and allows sending files
+ // using the fileupload API. The data parameter accepts an object which
+ // must have a files or fileInput property and can contain additional options:
+ // .fileupload('send', {files: filesList});
+ // The method returns a Promise object for the file upload call.
+ send: function (data) {
+ if (data && !this.options.disabled) {
+ if (data.fileInput && !data.files) {
+ var that = this,
+ dfd = $.Deferred(),
+ promise = dfd.promise(),
+ jqXHR,
+ aborted;
+ promise.abort = function () {
+ aborted = true;
+ if (jqXHR) {
+ return jqXHR.abort();
+ }
+ dfd.reject(null, 'abort', 'abort');
+ return promise;
+ };
+ this._getFileInputFiles(data.fileInput).always(
+ function (files) {
+ if (aborted) {
+ return;
+ }
+ if (!files.length) {
+ dfd.reject();
+ return;
+ }
+ data.files = files;
+ jqXHR = that._onSend(null, data);
+ jqXHR.then(
+ function (result, textStatus, jqXHR) {
+ dfd.resolve(result, textStatus, jqXHR);
+ },
+ function (jqXHR, textStatus, errorThrown) {
+ dfd.reject(jqXHR, textStatus, errorThrown);
+ }
+ );
+ }
+ );
+ return this._enhancePromise(promise);
+ }
+ data.files = $.makeArray(data.files);
+ if (data.files.length) {
+ return this._onSend(null, data);
+ }
+ }
+ return this._getXHRPromise(false, data && data.context);
+ }
+
+ });
+
+}));
\ No newline at end of file
diff --git a/public/editor/jquery.iframetransport.js b/public/editor/jquery.iframetransport.js
new file mode 100644
index 0000000..e2b4076
--- /dev/null
+++ b/public/editor/jquery.iframetransport.js
@@ -0,0 +1,217 @@
+/*
+ * jQuery Iframe Transport Plugin 1.8.3
+ * https://github.com/blueimp/jQuery-File-Upload
+ *
+ * Copyright 2011, Sebastian Tschan
+ * https://blueimp.net
+ *
+ * Licensed under the MIT license:
+ * http://www.opensource.org/licenses/MIT
+ */
+
+/* global define, require, window, document */
+
+(function (factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ // Register as an anonymous AMD module:
+ define(['jquery'], factory);
+ } else if (typeof exports === 'object') {
+ // Node/CommonJS:
+ factory(require('jquery'));
+ } else {
+ // Browser globals:
+ factory(window.jQuery);
+ }
+}(function ($) {
+ 'use strict';
+
+ // Helper variable to create unique names for the transport iframes:
+ var counter = 0;
+
+ // The iframe transport accepts four additional options:
+ // options.fileInput: a jQuery collection of file input fields
+ // options.paramName: the parameter name for the file form data,
+ // overrides the name property of the file input field(s),
+ // can be a string or an array of strings.
+ // options.formData: an array of objects with name and value properties,
+ // equivalent to the return data of .serializeArray(), e.g.:
+ // [{name: 'a', value: 1}, {name: 'b', value: 2}]
+ // options.initialIframeSrc: the URL of the initial iframe src,
+ // by default set to "javascript:false;"
+ $.ajaxTransport('iframe', function (options) {
+ if (options.async) {
+ // javascript:false as initial iframe src
+ // prevents warning popups on HTTPS in IE6:
+ /*jshint scripturl: true */
+ var initialIframeSrc = options.initialIframeSrc || 'javascript:false;',
+ /*jshint scripturl: false */
+ form,
+ iframe,
+ addParamChar;
+ return {
+ send: function (_, completeCallback) {
+ form = $('
');
+ form.attr('accept-charset', options.formAcceptCharset);
+ addParamChar = /\?/.test(options.url) ? '&' : '?';
+ // XDomainRequest only supports GET and POST:
+ if (options.type === 'DELETE') {
+ options.url = options.url + addParamChar + '_method=DELETE';
+ options.type = 'POST';
+ } else if (options.type === 'PUT') {
+ options.url = options.url + addParamChar + '_method=PUT';
+ options.type = 'POST';
+ } else if (options.type === 'PATCH') {
+ options.url = options.url + addParamChar + '_method=PATCH';
+ options.type = 'POST';
+ }
+ // IE versions below IE8 cannot set the name property of
+ // elements that have already been added to the DOM,
+ // so we set the name along with the iframe HTML markup:
+ counter += 1;
+ iframe = $(
+ '
'
+ ).bind('load', function () {
+ var fileInputClones,
+ paramNames = $.isArray(options.paramName) ?
+ options.paramName : [options.paramName];
+ iframe
+ .unbind('load')
+ .bind('load', function () {
+ var response;
+ // Wrap in a try/catch block to catch exceptions thrown
+ // when trying to access cross-domain iframe contents:
+ try {
+ response = iframe.contents();
+ // Google Chrome and Firefox do not throw an
+ // exception when calling iframe.contents() on
+ // cross-domain requests, so we unify the response:
+ if (!response.length || !response[0].firstChild) {
+ throw new Error();
+ }
+ } catch (e) {
+ response = undefined;
+ }
+ // The complete callback returns the
+ // iframe content document as response object:
+ completeCallback(
+ 200,
+ 'success',
+ {'iframe': response}
+ );
+ // Fix for IE endless progress bar activity bug
+ // (happens on form submits to iframe targets):
+ $('
')
+ .appendTo(form);
+ window.setTimeout(function () {
+ // Removing the form in a setTimeout call
+ // allows Chrome's developer tools to display
+ // the response result
+ form.remove();
+ }, 0);
+ });
+ form
+ .prop('target', iframe.prop('name'))
+ .prop('action', options.url)
+ .prop('method', options.type);
+ if (options.formData) {
+ $.each(options.formData, function (index, field) {
+ $('
')
+ .prop('name', field.name)
+ .val(field.value)
+ .appendTo(form);
+ });
+ }
+ if (options.fileInput && options.fileInput.length &&
+ options.type === 'POST') {
+ fileInputClones = options.fileInput.clone();
+ // Insert a clone for each file input field:
+ options.fileInput.after(function (index) {
+ return fileInputClones[index];
+ });
+ if (options.paramName) {
+ options.fileInput.each(function (index) {
+ $(this).prop(
+ 'name',
+ paramNames[index] || options.paramName
+ );
+ });
+ }
+ // Appending the file input fields to the hidden form
+ // removes them from their original location:
+ form
+ .append(options.fileInput)
+ .prop('enctype', 'multipart/form-data')
+ // enctype must be set as encoding for IE:
+ .prop('encoding', 'multipart/form-data');
+ // Remove the HTML5 form attribute from the input(s):
+ options.fileInput.removeAttr('form');
+ }
+ form.submit();
+ // Insert the file input fields at their original location
+ // by replacing the clones with the originals:
+ if (fileInputClones && fileInputClones.length) {
+ options.fileInput.each(function (index, input) {
+ var clone = $(fileInputClones[index]);
+ // Restore the original name and form properties:
+ $(input)
+ .prop('name', clone.prop('name'))
+ .attr('form', clone.attr('form'));
+ clone.replaceWith(input);
+ });
+ }
+ });
+ form.append(iframe).appendTo(document.body);
+ },
+ abort: function () {
+ if (iframe) {
+ // javascript:false as iframe src aborts the request
+ // and prevents warning popups on HTTPS in IE6.
+ // concat is used to avoid the "Script URL" JSLint error:
+ iframe
+ .unbind('load')
+ .prop('src', initialIframeSrc);
+ }
+ if (form) {
+ form.remove();
+ }
+ }
+ };
+ }
+ });
+
+ // The iframe transport returns the iframe content document as response.
+ // The following adds converters from iframe to text, json, html, xml
+ // and script.
+ // Please note that the Content-Type for JSON responses has to be text/plain
+ // or text/html, if the browser doesn't include application/json in the
+ // Accept header, else IE will show a download dialog.
+ // The Content-Type for XML responses on the other hand has to be always
+ // application/xml or text/xml, so IE properly parses the XML response.
+ // See also
+ // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation
+ $.ajaxSetup({
+ converters: {
+ 'iframe text': function (iframe) {
+ return iframe && $(iframe[0].body).text();
+ },
+ 'iframe json': function (iframe) {
+ return iframe && $.parseJSON($(iframe[0].body).text());
+ },
+ 'iframe html': function (iframe) {
+ return iframe && $(iframe[0].body).html();
+ },
+ 'iframe xml': function (iframe) {
+ var xmlDoc = iframe && iframe[0];
+ return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc :
+ $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) ||
+ $(xmlDoc.body).html());
+ },
+ 'iframe script': function (iframe) {
+ return iframe && $.globalEval($(iframe[0].body).text());
+ }
+ }
+ });
+
+}));
\ No newline at end of file
diff --git a/public/editor/localforage/localforage.js b/public/editor/localforage/localforage.js
new file mode 100644
index 0000000..42e5391
--- /dev/null
+++ b/public/editor/localforage/localforage.js
@@ -0,0 +1,2497 @@
+/*!
+ localForage -- Offline Storage, Improved
+ Version 1.2.2
+ https://mozilla.github.io/localForage
+ (c) 2013-2015 Mozilla, Apache License 2.0
+*/
+(function() {
+var define, requireModule, require, requirejs;
+
+(function() {
+ var registry = {}, seen = {};
+
+ define = function(name, deps, callback) {
+ registry[name] = { deps: deps, callback: callback };
+ };
+
+ requirejs = require = requireModule = function(name) {
+ requirejs._eak_seen = registry;
+
+ if (seen[name]) { return seen[name]; }
+ seen[name] = {};
+
+ if (!registry[name]) {
+ throw new Error("Could not find module " + name);
+ }
+
+ var mod = registry[name],
+ deps = mod.deps,
+ callback = mod.callback,
+ reified = [],
+ exports;
+
+ for (var i=0, l=deps.length; i
string data storage.
+ var BASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+
+ var SERIALIZED_MARKER = '__lfsc__:';
+ var SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER.length;
+
+ // OMG the serializations!
+ var TYPE_ARRAYBUFFER = 'arbf';
+ var TYPE_BLOB = 'blob';
+ var TYPE_INT8ARRAY = 'si08';
+ var TYPE_UINT8ARRAY = 'ui08';
+ var TYPE_UINT8CLAMPEDARRAY = 'uic8';
+ var TYPE_INT16ARRAY = 'si16';
+ var TYPE_INT32ARRAY = 'si32';
+ var TYPE_UINT16ARRAY = 'ur16';
+ var TYPE_UINT32ARRAY = 'ui32';
+ var TYPE_FLOAT32ARRAY = 'fl32';
+ var TYPE_FLOAT64ARRAY = 'fl64';
+ var TYPE_SERIALIZED_MARKER_LENGTH = SERIALIZED_MARKER_LENGTH +
+ TYPE_ARRAYBUFFER.length;
+
+ // Serialize a value, afterwards executing a callback (which usually
+ // instructs the `setItem()` callback/promise to be executed). This is how
+ // we store binary data with localStorage.
+ function serialize(value, callback) {
+ var valueString = '';
+ if (value) {
+ valueString = value.toString();
+ }
+
+ // Cannot use `value instanceof ArrayBuffer` or such here, as these
+ // checks fail when running the tests using casper.js...
+ //
+ // TODO: See why those tests fail and use a better solution.
+ if (value && (value.toString() === '[object ArrayBuffer]' ||
+ value.buffer &&
+ value.buffer.toString() === '[object ArrayBuffer]')) {
+ // Convert binary arrays to a string and prefix the string with
+ // a special marker.
+ var buffer;
+ var marker = SERIALIZED_MARKER;
+
+ if (value instanceof ArrayBuffer) {
+ buffer = value;
+ marker += TYPE_ARRAYBUFFER;
+ } else {
+ buffer = value.buffer;
+
+ if (valueString === '[object Int8Array]') {
+ marker += TYPE_INT8ARRAY;
+ } else if (valueString === '[object Uint8Array]') {
+ marker += TYPE_UINT8ARRAY;
+ } else if (valueString === '[object Uint8ClampedArray]') {
+ marker += TYPE_UINT8CLAMPEDARRAY;
+ } else if (valueString === '[object Int16Array]') {
+ marker += TYPE_INT16ARRAY;
+ } else if (valueString === '[object Uint16Array]') {
+ marker += TYPE_UINT16ARRAY;
+ } else if (valueString === '[object Int32Array]') {
+ marker += TYPE_INT32ARRAY;
+ } else if (valueString === '[object Uint32Array]') {
+ marker += TYPE_UINT32ARRAY;
+ } else if (valueString === '[object Float32Array]') {
+ marker += TYPE_FLOAT32ARRAY;
+ } else if (valueString === '[object Float64Array]') {
+ marker += TYPE_FLOAT64ARRAY;
+ } else {
+ callback(new Error('Failed to get type for BinaryArray'));
+ }
+ }
+
+ callback(marker + bufferToString(buffer));
+ } else if (valueString === '[object Blob]') {
+ // Conver the blob to a binaryArray and then to a string.
+ var fileReader = new FileReader();
+
+ fileReader.onload = function() {
+ var str = bufferToString(this.result);
+
+ callback(SERIALIZED_MARKER + TYPE_BLOB + str);
+ };
+
+ fileReader.readAsArrayBuffer(value);
+ } else {
+ try {
+ callback(JSON.stringify(value));
+ } catch (e) {
+ window.console.error("Couldn't convert value into a JSON " +
+ 'string: ', value);
+
+ callback(null, e);
+ }
+ }
+ }
+
+ // Deserialize data we've inserted into a value column/field. We place
+ // special markers into our strings to mark them as encoded; this isn't
+ // as nice as a meta field, but it's the only sane thing we can do whilst
+ // keeping localStorage support intact.
+ //
+ // Oftentimes this will just deserialize JSON content, but if we have a
+ // special marker (SERIALIZED_MARKER, defined above), we will extract
+ // some kind of arraybuffer/binary data/typed array out of the string.
+ function deserialize(value) {
+ // If we haven't marked this string as being specially serialized (i.e.
+ // something other than serialized JSON), we can just return it and be
+ // done with it.
+ if (value.substring(0,
+ SERIALIZED_MARKER_LENGTH) !== SERIALIZED_MARKER) {
+ return JSON.parse(value);
+ }
+
+ // The following code deals with deserializing some kind of Blob or
+ // TypedArray. First we separate out the type of data we're dealing
+ // with from the data itself.
+ var serializedString = value.substring(TYPE_SERIALIZED_MARKER_LENGTH);
+ var type = value.substring(SERIALIZED_MARKER_LENGTH,
+ TYPE_SERIALIZED_MARKER_LENGTH);
+
+ var buffer = stringToBuffer(serializedString);
+
+ // Return the right type based on the code/type set during
+ // serialization.
+ switch (type) {
+ case TYPE_ARRAYBUFFER:
+ return buffer;
+ case TYPE_BLOB:
+ return new Blob([buffer]);
+ case TYPE_INT8ARRAY:
+ return new Int8Array(buffer);
+ case TYPE_UINT8ARRAY:
+ return new Uint8Array(buffer);
+ case TYPE_UINT8CLAMPEDARRAY:
+ return new Uint8ClampedArray(buffer);
+ case TYPE_INT16ARRAY:
+ return new Int16Array(buffer);
+ case TYPE_UINT16ARRAY:
+ return new Uint16Array(buffer);
+ case TYPE_INT32ARRAY:
+ return new Int32Array(buffer);
+ case TYPE_UINT32ARRAY:
+ return new Uint32Array(buffer);
+ case TYPE_FLOAT32ARRAY:
+ return new Float32Array(buffer);
+ case TYPE_FLOAT64ARRAY:
+ return new Float64Array(buffer);
+ default:
+ throw new Error('Unkown type: ' + type);
+ }
+ }
+
+ function stringToBuffer(serializedString) {
+ // Fill the string into a ArrayBuffer.
+ var bufferLength = serializedString.length * 0.75;
+ var len = serializedString.length;
+ var i;
+ var p = 0;
+ var encoded1, encoded2, encoded3, encoded4;
+
+ if (serializedString[serializedString.length - 1] === '=') {
+ bufferLength--;
+ if (serializedString[serializedString.length - 2] === '=') {
+ bufferLength--;
+ }
+ }
+
+ var buffer = new ArrayBuffer(bufferLength);
+ var bytes = new Uint8Array(buffer);
+
+ for (i = 0; i < len; i+=4) {
+ encoded1 = BASE_CHARS.indexOf(serializedString[i]);
+ encoded2 = BASE_CHARS.indexOf(serializedString[i+1]);
+ encoded3 = BASE_CHARS.indexOf(serializedString[i+2]);
+ encoded4 = BASE_CHARS.indexOf(serializedString[i+3]);
+
+ /*jslint bitwise: true */
+ bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
+ bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
+ bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
+ }
+ return buffer;
+ }
+
+ // Converts a buffer to a string to store, serialized, in the backend
+ // storage library.
+ function bufferToString(buffer) {
+ // base64-arraybuffer
+ var bytes = new Uint8Array(buffer);
+ var base64String = '';
+ var i;
+
+ for (i = 0; i < bytes.length; i += 3) {
+ /*jslint bitwise: true */
+ base64String += BASE_CHARS[bytes[i] >> 2];
+ base64String += BASE_CHARS[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
+ base64String += BASE_CHARS[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
+ base64String += BASE_CHARS[bytes[i + 2] & 63];
+ }
+
+ if ((bytes.length % 3) === 2) {
+ base64String = base64String.substring(0, base64String.length - 1) + '=';
+ } else if (bytes.length % 3 === 1) {
+ base64String = base64String.substring(0, base64String.length - 2) + '==';
+ }
+
+ return base64String;
+ }
+
+ var localforageSerializer = {
+ serialize: serialize,
+ deserialize: deserialize,
+ stringToBuffer: stringToBuffer,
+ bufferToString: bufferToString
+ };
+
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = localforageSerializer;
+ } else if (typeof define === 'function' && define.amd) {
+ define('localforageSerializer', function() {
+ return localforageSerializer;
+ });
+ } else {
+ this.localforageSerializer = localforageSerializer;
+ }
+}).call(window);
+// Some code originally from async_storage.js in
+// [Gaia](https://github.com/mozilla-b2g/gaia).
+(function() {
+ 'use strict';
+
+ // Originally found in https://github.com/mozilla-b2g/gaia/blob/e8f624e4cc9ea945727278039b3bc9bcb9f8667a/shared/js/async_storage.js
+
+ // Promises!
+ var Promise = (typeof module !== 'undefined' && module.exports) ?
+ require('promise') : this.Promise;
+
+ // Initialize IndexedDB; fall back to vendor-prefixed versions if needed.
+ var indexedDB = indexedDB || this.indexedDB || this.webkitIndexedDB ||
+ this.mozIndexedDB || this.OIndexedDB ||
+ this.msIndexedDB;
+
+ // If IndexedDB isn't available, we get outta here!
+ if (!indexedDB) {
+ return;
+ }
+
+ // Open the IndexedDB database (automatically creates one if one didn't
+ // previously exist), using any options set in the config.
+ function _initStorage(options) {
+ var self = this;
+ var dbInfo = {
+ db: null
+ };
+
+ if (options) {
+ for (var i in options) {
+ dbInfo[i] = options[i];
+ }
+ }
+
+ return new Promise(function(resolve, reject) {
+ var openreq = indexedDB.open(dbInfo.name, dbInfo.version);
+ openreq.onerror = function() {
+ reject(openreq.error);
+ };
+ openreq.onupgradeneeded = function() {
+ // First time setup: create an empty object store
+ openreq.result.createObjectStore(dbInfo.storeName);
+ };
+ openreq.onsuccess = function() {
+ dbInfo.db = openreq.result;
+ self._dbInfo = dbInfo;
+ resolve();
+ };
+ });
+ }
+
+ function getItem(key, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly')
+ .objectStore(dbInfo.storeName);
+ var req = store.get(key);
+
+ req.onsuccess = function() {
+ var value = req.result;
+ if (value === undefined) {
+ value = null;
+ }
+
+ resolve(value);
+ };
+
+ req.onerror = function() {
+ reject(req.error);
+ };
+ })["catch"](reject);
+ });
+
+ executeDeferedCallback(promise, callback);
+ return promise;
+ }
+
+ // Iterate over all items stored in database.
+ function iterate(iterator, callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly')
+ .objectStore(dbInfo.storeName);
+
+ var req = store.openCursor();
+ var iterationNumber = 1;
+
+ req.onsuccess = function() {
+ var cursor = req.result;
+
+ if (cursor) {
+ var result = iterator(cursor.value, cursor.key, iterationNumber++);
+
+ if (result !== void(0)) {
+ resolve(result);
+ } else {
+ cursor["continue"]();
+ }
+ } else {
+ resolve();
+ }
+ };
+
+ req.onerror = function() {
+ reject(req.error);
+ };
+ })["catch"](reject);
+ });
+
+ executeDeferedCallback(promise, callback);
+
+ return promise;
+ }
+
+ function setItem(key, value, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
+ var store = transaction.objectStore(dbInfo.storeName);
+
+ // The reason we don't _save_ null is because IE 10 does
+ // not support saving the `null` type in IndexedDB. How
+ // ironic, given the bug below!
+ // See: https://github.com/mozilla/localForage/issues/161
+ if (value === null) {
+ value = undefined;
+ }
+
+ var req = store.put(value, key);
+ transaction.oncomplete = function() {
+ // Cast to undefined so the value passed to
+ // callback/promise is the same as what one would get out
+ // of `getItem()` later. This leads to some weirdness
+ // (setItem('foo', undefined) will return `null`), but
+ // it's not my fault localStorage is our baseline and that
+ // it's weird.
+ if (value === undefined) {
+ value = null;
+ }
+
+ resolve(value);
+ };
+ transaction.onabort = transaction.onerror = function() {
+ reject(req.error);
+ };
+ })["catch"](reject);
+ });
+
+ executeDeferedCallback(promise, callback);
+ return promise;
+ }
+
+ function removeItem(key, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
+ var store = transaction.objectStore(dbInfo.storeName);
+
+ // We use a Grunt task to make this safe for IE and some
+ // versions of Android (including those used by Cordova).
+ // Normally IE won't like `.delete()` and will insist on
+ // using `['delete']()`, but we have a build step that
+ // fixes this for us now.
+ var req = store["delete"](key);
+ transaction.oncomplete = function() {
+ resolve();
+ };
+
+ transaction.onerror = function() {
+ reject(req.error);
+ };
+
+ // The request will be aborted if we've exceeded our storage
+ // space. In this case, we will reject with a specific
+ // "QuotaExceededError".
+ transaction.onabort = function(event) {
+ var error = event.target.error;
+ if (error === 'QuotaExceededError') {
+ reject(error);
+ }
+ };
+ })["catch"](reject);
+ });
+
+ executeDeferedCallback(promise, callback);
+ return promise;
+ }
+
+ function clear(callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var transaction = dbInfo.db.transaction(dbInfo.storeName, 'readwrite');
+ var store = transaction.objectStore(dbInfo.storeName);
+ var req = store.clear();
+
+ transaction.oncomplete = function() {
+ resolve();
+ };
+
+ transaction.onabort = transaction.onerror = function() {
+ reject(req.error);
+ };
+ })["catch"](reject);
+ });
+
+ executeDeferedCallback(promise, callback);
+ return promise;
+ }
+
+ function length(callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly')
+ .objectStore(dbInfo.storeName);
+ var req = store.count();
+
+ req.onsuccess = function() {
+ resolve(req.result);
+ };
+
+ req.onerror = function() {
+ reject(req.error);
+ };
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function key(n, callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ if (n < 0) {
+ resolve(null);
+
+ return;
+ }
+
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly')
+ .objectStore(dbInfo.storeName);
+
+ var advanced = false;
+ var req = store.openCursor();
+ req.onsuccess = function() {
+ var cursor = req.result;
+ if (!cursor) {
+ // this means there weren't enough keys
+ resolve(null);
+
+ return;
+ }
+
+ if (n === 0) {
+ // We have the first key, return it if that's what they
+ // wanted.
+ resolve(cursor.key);
+ } else {
+ if (!advanced) {
+ // Otherwise, ask the cursor to skip ahead n
+ // records.
+ advanced = true;
+ cursor.advance(n);
+ } else {
+ // When we get here, we've got the nth key.
+ resolve(cursor.key);
+ }
+ }
+ };
+
+ req.onerror = function() {
+ reject(req.error);
+ };
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function keys(callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var store = dbInfo.db.transaction(dbInfo.storeName, 'readonly')
+ .objectStore(dbInfo.storeName);
+
+ var req = store.openCursor();
+ var keys = [];
+
+ req.onsuccess = function() {
+ var cursor = req.result;
+
+ if (!cursor) {
+ resolve(keys);
+ return;
+ }
+
+ keys.push(cursor.key);
+ cursor["continue"]();
+ };
+
+ req.onerror = function() {
+ reject(req.error);
+ };
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function executeCallback(promise, callback) {
+ if (callback) {
+ promise.then(function(result) {
+ callback(null, result);
+ }, function(error) {
+ callback(error);
+ });
+ }
+ }
+
+ function executeDeferedCallback(promise, callback) {
+ if (callback) {
+ promise.then(function(result) {
+ deferCallback(callback, result);
+ }, function(error) {
+ callback(error);
+ });
+ }
+ }
+
+ // Under Chrome the callback is called before the changes (save, clear)
+ // are actually made. So we use a defer function which wait that the
+ // call stack to be empty.
+ // For more info : https://github.com/mozilla/localForage/issues/175
+ // Pull request : https://github.com/mozilla/localForage/pull/178
+ function deferCallback(callback, result) {
+ if (callback) {
+ return setTimeout(function() {
+ return callback(null, result);
+ }, 0);
+ }
+ }
+
+ var asyncStorage = {
+ _driver: 'asyncStorage',
+ _initStorage: _initStorage,
+ iterate: iterate,
+ getItem: getItem,
+ setItem: setItem,
+ removeItem: removeItem,
+ clear: clear,
+ length: length,
+ key: key,
+ keys: keys
+ };
+
+ if (typeof module !== 'undefined' && module.exports) {
+ module.exports = asyncStorage;
+ } else if (typeof define === 'function' && define.amd) {
+ define('asyncStorage', function() {
+ return asyncStorage;
+ });
+ } else {
+ this.asyncStorage = asyncStorage;
+ }
+}).call(window);
+// If IndexedDB isn't available, we'll fall back to localStorage.
+// Note that this will have considerable performance and storage
+// side-effects (all data will be serialized on save and only data that
+// can be converted to a string via `JSON.stringify()` will be saved).
+(function() {
+ 'use strict';
+
+ // Promises!
+ var Promise = (typeof module !== 'undefined' && module.exports) ?
+ require('promise') : this.Promise;
+
+ var globalObject = this;
+ var serializer = null;
+ var localStorage = null;
+
+ // If the app is running inside a Google Chrome packaged webapp, or some
+ // other context where localStorage isn't available, we don't use
+ // localStorage. This feature detection is preferred over the old
+ // `if (window.chrome && window.chrome.runtime)` code.
+ // See: https://github.com/mozilla/localForage/issues/68
+ try {
+ // If localStorage isn't available, we get outta here!
+ // This should be inside a try catch
+ if (!this.localStorage || !('setItem' in this.localStorage)) {
+ return;
+ }
+ // Initialize localStorage and create a variable to use throughout
+ // the code.
+ localStorage = this.localStorage;
+ } catch (e) {
+ return;
+ }
+
+ var ModuleType = {
+ DEFINE: 1,
+ EXPORT: 2,
+ WINDOW: 3
+ };
+
+ // Attaching to window (i.e. no module loader) is the assumed,
+ // simple default.
+ var moduleType = ModuleType.WINDOW;
+
+ // Find out what kind of module setup we have; if none, we'll just attach
+ // localForage to the main window.
+ if (typeof module !== 'undefined' && module.exports) {
+ moduleType = ModuleType.EXPORT;
+ } else if (typeof define === 'function' && define.amd) {
+ moduleType = ModuleType.DEFINE;
+ }
+
+ // Config the localStorage backend, using options set in the config.
+ function _initStorage(options) {
+ var self = this;
+ var dbInfo = {};
+ if (options) {
+ for (var i in options) {
+ dbInfo[i] = options[i];
+ }
+ }
+
+ dbInfo.keyPrefix = dbInfo.name + '/';
+
+ self._dbInfo = dbInfo;
+
+ var serializerPromise = new Promise(function(resolve/*, reject*/) {
+ // We allow localForage to be declared as a module or as a
+ // library available without AMD/require.js.
+ if (moduleType === ModuleType.DEFINE) {
+ require(['localforageSerializer'], resolve);
+ } else if (moduleType === ModuleType.EXPORT) {
+ // Making it browserify friendly
+ resolve(require('./../utils/serializer'));
+ } else {
+ resolve(globalObject.localforageSerializer);
+ }
+ });
+
+ return serializerPromise.then(function(lib) {
+ serializer = lib;
+ return Promise.resolve();
+ });
+ }
+
+ // Remove all keys from the datastore, effectively destroying all data in
+ // the app's key/value store!
+ function clear(callback) {
+ var self = this;
+ var promise = self.ready().then(function() {
+ var keyPrefix = self._dbInfo.keyPrefix;
+
+ for (var i = localStorage.length - 1; i >= 0; i--) {
+ var key = localStorage.key(i);
+
+ if (key.indexOf(keyPrefix) === 0) {
+ localStorage.removeItem(key);
+ }
+ }
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Retrieve an item from the store. Unlike the original async_storage
+ // library in Gaia, we don't modify return values at all. If a key's value
+ // is `undefined`, we pass that value to the callback function.
+ function getItem(key, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var result = localStorage.getItem(dbInfo.keyPrefix + key);
+
+ // If a result was found, parse it from the serialized
+ // string into a JS object. If result isn't truthy, the key
+ // is likely undefined and we'll pass it straight to the
+ // callback.
+ if (result) {
+ result = serializer.deserialize(result);
+ }
+
+ return result;
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Iterate over all items in the store.
+ function iterate(iterator, callback) {
+ var self = this;
+
+ var promise = self.ready().then(function() {
+ var keyPrefix = self._dbInfo.keyPrefix;
+ var keyPrefixLength = keyPrefix.length;
+ var length = localStorage.length;
+
+ for (var i = 0; i < length; i++) {
+ var key = localStorage.key(i);
+ var value = localStorage.getItem(key);
+
+ // If a result was found, parse it from the serialized
+ // string into a JS object. If result isn't truthy, the
+ // key is likely undefined and we'll pass it straight
+ // to the iterator.
+ if (value) {
+ value = serializer.deserialize(value);
+ }
+
+ value = iterator(value, key.substring(keyPrefixLength), i + 1);
+
+ if (value !== void(0)) {
+ return value;
+ }
+ }
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Same as localStorage's key() method, except takes a callback.
+ function key(n, callback) {
+ var self = this;
+ var promise = self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var result;
+ try {
+ result = localStorage.key(n);
+ } catch (error) {
+ result = null;
+ }
+
+ // Remove the prefix from the key, if a key is found.
+ if (result) {
+ result = result.substring(dbInfo.keyPrefix.length);
+ }
+
+ return result;
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function keys(callback) {
+ var self = this;
+ var promise = self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ var length = localStorage.length;
+ var keys = [];
+
+ for (var i = 0; i < length; i++) {
+ if (localStorage.key(i).indexOf(dbInfo.keyPrefix) === 0) {
+ keys.push(localStorage.key(i).substring(dbInfo.keyPrefix.length));
+ }
+ }
+
+ return keys;
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Supply the number of keys in the datastore to the callback function.
+ function length(callback) {
+ var self = this;
+ var promise = self.keys().then(function(keys) {
+ return keys.length;
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Remove an item from the store, nice and simple.
+ function removeItem(key, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ localStorage.removeItem(dbInfo.keyPrefix + key);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Set a key's value and run an optional callback once the value is set.
+ // Unlike Gaia's implementation, the callback function is passed the value,
+ // in case you want to operate on that value only after you're sure it
+ // saved, or something like that.
+ function setItem(key, value, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = self.ready().then(function() {
+ // Convert undefined values to null.
+ // https://github.com/mozilla/localForage/pull/42
+ if (value === undefined) {
+ value = null;
+ }
+
+ // Save the original value to pass to the callback.
+ var originalValue = value;
+
+ return new Promise(function(resolve, reject) {
+ serializer.serialize(value, function(value, error) {
+ if (error) {
+ reject(error);
+ } else {
+ try {
+ var dbInfo = self._dbInfo;
+ localStorage.setItem(dbInfo.keyPrefix + key, value);
+ resolve(originalValue);
+ } catch (e) {
+ // localStorage capacity exceeded.
+ // TODO: Make this a specific error/event.
+ if (e.name === 'QuotaExceededError' ||
+ e.name === 'NS_ERROR_DOM_QUOTA_REACHED') {
+ reject(e);
+ }
+ reject(e);
+ }
+ }
+ });
+ });
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function executeCallback(promise, callback) {
+ if (callback) {
+ promise.then(function(result) {
+ callback(null, result);
+ }, function(error) {
+ callback(error);
+ });
+ }
+ }
+
+ var localStorageWrapper = {
+ _driver: 'localStorageWrapper',
+ _initStorage: _initStorage,
+ // Default API, from Gaia/localStorage.
+ iterate: iterate,
+ getItem: getItem,
+ setItem: setItem,
+ removeItem: removeItem,
+ clear: clear,
+ length: length,
+ key: key,
+ keys: keys
+ };
+
+ if (moduleType === ModuleType.EXPORT) {
+ module.exports = localStorageWrapper;
+ } else if (moduleType === ModuleType.DEFINE) {
+ define('localStorageWrapper', function() {
+ return localStorageWrapper;
+ });
+ } else {
+ this.localStorageWrapper = localStorageWrapper;
+ }
+}).call(window);
+/*
+ * Includes code from:
+ *
+ * base64-arraybuffer
+ * https://github.com/niklasvh/base64-arraybuffer
+ *
+ * Copyright (c) 2012 Niklas von Hertzen
+ * Licensed under the MIT license.
+ */
+(function() {
+ 'use strict';
+
+ // Promises!
+ var Promise = (typeof module !== 'undefined' && module.exports) ?
+ require('promise') : this.Promise;
+
+ var globalObject = this;
+ var serializer = null;
+ var openDatabase = this.openDatabase;
+
+ // If WebSQL methods aren't available, we can stop now.
+ if (!openDatabase) {
+ return;
+ }
+
+ var ModuleType = {
+ DEFINE: 1,
+ EXPORT: 2,
+ WINDOW: 3
+ };
+
+ // Attaching to window (i.e. no module loader) is the assumed,
+ // simple default.
+ var moduleType = ModuleType.WINDOW;
+
+ // Find out what kind of module setup we have; if none, we'll just attach
+ // localForage to the main window.
+ if (typeof module !== 'undefined' && module.exports) {
+ moduleType = ModuleType.EXPORT;
+ } else if (typeof define === 'function' && define.amd) {
+ moduleType = ModuleType.DEFINE;
+ }
+
+ // Open the WebSQL database (automatically creates one if one didn't
+ // previously exist), using any options set in the config.
+ function _initStorage(options) {
+ var self = this;
+ var dbInfo = {
+ db: null
+ };
+
+ if (options) {
+ for (var i in options) {
+ dbInfo[i] = typeof(options[i]) !== 'string' ?
+ options[i].toString() : options[i];
+ }
+ }
+
+ var serializerPromise = new Promise(function(resolve/*, reject*/) {
+ // We allow localForage to be declared as a module or as a
+ // library available without AMD/require.js.
+ if (moduleType === ModuleType.DEFINE) {
+ require(['localforageSerializer'], resolve);
+ } else if (moduleType === ModuleType.EXPORT) {
+ // Making it browserify friendly
+ resolve(require('./../utils/serializer'));
+ } else {
+ resolve(globalObject.localforageSerializer);
+ }
+ });
+
+ var dbInfoPromise = new Promise(function(resolve, reject) {
+ // Open the database; the openDatabase API will automatically
+ // create it for us if it doesn't exist.
+ try {
+ dbInfo.db = openDatabase(dbInfo.name, String(dbInfo.version),
+ dbInfo.description, dbInfo.size);
+ } catch (e) {
+ return self.setDriver(self.LOCALSTORAGE).then(function() {
+ return self._initStorage(options);
+}).then(resolve)["catch"](reject);
+ }
+
+ // Create our key/value table if it doesn't exist.
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('CREATE TABLE IF NOT EXISTS ' + dbInfo.storeName +
+ ' (id INTEGER PRIMARY KEY, key unique, value)', [],
+ function() {
+ self._dbInfo = dbInfo;
+ resolve();
+ }, function(t, error) {
+ reject(error);
+ });
+ });
+ });
+
+ return serializerPromise.then(function(lib) {
+ serializer = lib;
+ return dbInfoPromise;
+ });
+ }
+
+ function getItem(key, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('SELECT * FROM ' + dbInfo.storeName +
+ ' WHERE key = ? LIMIT 1', [key],
+ function(t, results) {
+ var result = results.rows.length ?
+ results.rows.item(0).value : null;
+
+ // Check to see if this is serialized content we need to
+ // unpack.
+ if (result) {
+ result = serializer.deserialize(result);
+ }
+
+ resolve(result);
+ }, function(t, error) {
+
+ reject(error);
+ });
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function iterate(iterator, callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('SELECT * FROM ' + dbInfo.storeName, [],
+ function(t, results) {
+ var rows = results.rows;
+ var length = rows.length;
+
+ for (var i = 0; i < length; i++) {
+ var item = rows.item(i);
+ var result = item.value;
+
+ // Check to see if this is serialized content
+ // we need to unpack.
+ if (result) {
+ result = serializer.deserialize(result);
+ }
+
+ result = iterator(result, item.key, i + 1);
+
+ // void(0) prevents problems with redefinition
+ // of `undefined`.
+ if (result !== void(0)) {
+ resolve(result);
+ return;
+ }
+ }
+
+ resolve();
+ }, function(t, error) {
+ reject(error);
+ });
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function setItem(key, value, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ // The localStorage API doesn't return undefined values in an
+ // "expected" way, so undefined is always cast to null in all
+ // drivers. See: https://github.com/mozilla/localForage/pull/42
+ if (value === undefined) {
+ value = null;
+ }
+
+ // Save the original value to pass to the callback.
+ var originalValue = value;
+
+ serializer.serialize(value, function(value, error) {
+ if (error) {
+ reject(error);
+ } else {
+ var dbInfo = self._dbInfo;
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('INSERT OR REPLACE INTO ' +
+ dbInfo.storeName +
+ ' (key, value) VALUES (?, ?)',
+ [key, value], function() {
+ resolve(originalValue);
+ }, function(t, error) {
+ reject(error);
+ });
+ }, function(sqlError) { // The transaction failed; check
+ // to see if it's a quota error.
+ if (sqlError.code === sqlError.QUOTA_ERR) {
+ // We reject the callback outright for now, but
+ // it's worth trying to re-run the transaction.
+ // Even if the user accepts the prompt to use
+ // more storage on Safari, this error will
+ // be called.
+ //
+ // TODO: Try to re-run the transaction.
+ reject(sqlError);
+ }
+ });
+ }
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function removeItem(key, callback) {
+ var self = this;
+
+ // Cast the key to a string, as that's all we can set as a key.
+ if (typeof key !== 'string') {
+ window.console.warn(key +
+ ' used as a key, but it is not a string.');
+ key = String(key);
+ }
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('DELETE FROM ' + dbInfo.storeName +
+ ' WHERE key = ?', [key], function() {
+
+ resolve();
+ }, function(t, error) {
+
+ reject(error);
+ });
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Deletes every item in the table.
+ // TODO: Find out if this resets the AUTO_INCREMENT number.
+ function clear(callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('DELETE FROM ' + dbInfo.storeName, [],
+ function() {
+ resolve();
+ }, function(t, error) {
+ reject(error);
+ });
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Does a simple `COUNT(key)` to get the number of items stored in
+ // localForage.
+ function length(callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ dbInfo.db.transaction(function(t) {
+ // Ahhh, SQL makes this one soooooo easy.
+ t.executeSql('SELECT COUNT(key) as c FROM ' +
+ dbInfo.storeName, [], function(t, results) {
+ var result = results.rows.item(0).c;
+
+ resolve(result);
+ }, function(t, error) {
+
+ reject(error);
+ });
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ // Return the key located at key index X; essentially gets the key from a
+ // `WHERE id = ?`. This is the most efficient way I can think to implement
+ // this rarely-used (in my experience) part of the API, but it can seem
+ // inconsistent, because we do `INSERT OR REPLACE INTO` on `setItem()`, so
+ // the ID of each key will change every time it's updated. Perhaps a stored
+ // procedure for the `setItem()` SQL would solve this problem?
+ // TODO: Don't change ID on `setItem()`.
+ function key(n, callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('SELECT key FROM ' + dbInfo.storeName +
+ ' WHERE id = ? LIMIT 1', [n + 1],
+ function(t, results) {
+ var result = results.rows.length ?
+ results.rows.item(0).key : null;
+ resolve(result);
+ }, function(t, error) {
+ reject(error);
+ });
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function keys(callback) {
+ var self = this;
+
+ var promise = new Promise(function(resolve, reject) {
+ self.ready().then(function() {
+ var dbInfo = self._dbInfo;
+ dbInfo.db.transaction(function(t) {
+ t.executeSql('SELECT key FROM ' + dbInfo.storeName, [],
+ function(t, results) {
+ var keys = [];
+
+ for (var i = 0; i < results.rows.length; i++) {
+ keys.push(results.rows.item(i).key);
+ }
+
+ resolve(keys);
+ }, function(t, error) {
+
+ reject(error);
+ });
+ });
+ })["catch"](reject);
+ });
+
+ executeCallback(promise, callback);
+ return promise;
+ }
+
+ function executeCallback(promise, callback) {
+ if (callback) {
+ promise.then(function(result) {
+ callback(null, result);
+ }, function(error) {
+ callback(error);
+ });
+ }
+ }
+
+ var webSQLStorage = {
+ _driver: 'webSQLStorage',
+ _initStorage: _initStorage,
+ iterate: iterate,
+ getItem: getItem,
+ setItem: setItem,
+ removeItem: removeItem,
+ clear: clear,
+ length: length,
+ key: key,
+ keys: keys
+ };
+
+ if (moduleType === ModuleType.DEFINE) {
+ define('webSQLStorage', function() {
+ return webSQLStorage;
+ });
+ } else if (moduleType === ModuleType.EXPORT) {
+ module.exports = webSQLStorage;
+ } else {
+ this.webSQLStorage = webSQLStorage;
+ }
+}).call(window);
+(function() {
+ 'use strict';
+
+ // Promises!
+ var Promise = (typeof module !== 'undefined' && module.exports) ?
+ require('promise') : this.Promise;
+
+ // Custom drivers are stored here when `defineDriver()` is called.
+ // They are shared across all instances of localForage.
+ var CustomDrivers = {};
+
+ var DriverType = {
+ INDEXEDDB: 'asyncStorage',
+ LOCALSTORAGE: 'localStorageWrapper',
+ WEBSQL: 'webSQLStorage'
+ };
+
+ var DefaultDriverOrder = [
+ DriverType.INDEXEDDB,
+ DriverType.WEBSQL,
+ DriverType.LOCALSTORAGE
+ ];
+
+ var LibraryMethods = [
+ 'clear',
+ 'getItem',
+ 'iterate',
+ 'key',
+ 'keys',
+ 'length',
+ 'removeItem',
+ 'setItem'
+ ];
+
+ var ModuleType = {
+ DEFINE: 1,
+ EXPORT: 2,
+ WINDOW: 3
+ };
+
+ var DefaultConfig = {
+ description: '',
+ driver: DefaultDriverOrder.slice(),
+ name: 'localforage',
+ // Default DB size is _JUST UNDER_ 5MB, as it's the highest size
+ // we can use without a prompt.
+ size: 4980736,
+ storeName: 'keyvaluepairs',
+ version: 1.0
+ };
+
+ // Attaching to window (i.e. no module loader) is the assumed,
+ // simple default.
+ var moduleType = ModuleType.WINDOW;
+
+ // Find out what kind of module setup we have; if none, we'll just attach
+ // localForage to the main window.
+ if (typeof module !== 'undefined' && module.exports) {
+ moduleType = ModuleType.EXPORT;
+ } else if (typeof define === 'function' && define.amd) {
+ moduleType = ModuleType.DEFINE;
+ }
+
+ // Check to see if IndexedDB is available and if it is the latest
+ // implementation; it's our preferred backend library. We use "_spec_test"
+ // as the name of the database because it's not the one we'll operate on,
+ // but it's useful to make sure its using the right spec.
+ // See: https://github.com/mozilla/localForage/issues/128
+ var driverSupport = (function(self) {
+ // Initialize IndexedDB; fall back to vendor-prefixed versions
+ // if needed.
+ var indexedDB = indexedDB || self.indexedDB || self.webkitIndexedDB ||
+ self.mozIndexedDB || self.OIndexedDB ||
+ self.msIndexedDB;
+
+ var result = {};
+
+ result[DriverType.WEBSQL] = !!self.openDatabase;
+ result[DriverType.INDEXEDDB] = !!(function() {
+ // We mimic PouchDB here; just UA test for Safari (which, as of
+ // iOS 8/Yosemite, doesn't properly support IndexedDB).
+ // IndexedDB support is broken and different from Blink's.
+ // This is faster than the test case (and it's sync), so we just
+ // do this. *SIGH*
+ // http://bl.ocks.org/nolanlawson/raw/c83e9039edf2278047e9/
+ //
+ // We test for openDatabase because IE Mobile identifies itself
+ // as Safari. Oh the lulz...
+ if (typeof self.openDatabase !== 'undefined' && self.navigator &&
+ self.navigator.userAgent &&
+ /Safari/.test(self.navigator.userAgent) &&
+ !/Chrome/.test(self.navigator.userAgent)) {
+ return false;
+ }
+ try {
+ return indexedDB &&
+ typeof indexedDB.open === 'function' &&
+ // Some Samsung/HTC Android 4.0-4.3 devices
+ // have older IndexedDB specs; if this isn't available
+ // their IndexedDB is too old for us to use.
+ // (Replaces the onupgradeneeded test.)
+ typeof self.IDBKeyRange !== 'undefined';
+ } catch (e) {
+ return false;
+ }
+ })();
+
+ result[DriverType.LOCALSTORAGE] = !!(function() {
+ try {
+ return (self.localStorage &&
+ ('setItem' in self.localStorage) &&
+ (self.localStorage.setItem));
+ } catch (e) {
+ return false;
+ }
+ })();
+
+ return result;
+ })(this);
+
+ var isArray = Array.isArray || function(arg) {
+ return Object.prototype.toString.call(arg) === '[object Array]';
+ };
+
+ function callWhenReady(localForageInstance, libraryMethod) {
+ localForageInstance[libraryMethod] = function() {
+ var _args = arguments;
+ return localForageInstance.ready().then(function() {
+ return localForageInstance[libraryMethod].apply(localForageInstance, _args);
+ });
+ };
+ }
+
+ function extend() {
+ for (var i = 1; i < arguments.length; i++) {
+ var arg = arguments[i];
+
+ if (arg) {
+ for (var key in arg) {
+ if (arg.hasOwnProperty(key)) {
+ if (isArray(arg[key])) {
+ arguments[0][key] = arg[key].slice();
+ } else {
+ arguments[0][key] = arg[key];
+ }
+ }
+ }
+ }
+ }
+
+ return arguments[0];
+ }
+
+ function isLibraryDriver(driverName) {
+ for (var driver in DriverType) {
+ if (DriverType.hasOwnProperty(driver) &&
+ DriverType[driver] === driverName) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ var globalObject = this;
+
+ function LocalForage(options) {
+ this._config = extend({}, DefaultConfig, options);
+ this._driverSet = null;
+ this._ready = false;
+ this._dbInfo = null;
+
+ // Add a stub for each driver API method that delays the call to the
+ // corresponding driver method until localForage is ready. These stubs
+ // will be replaced by the driver methods as soon as the driver is
+ // loaded, so there is no performance impact.
+ for (var i = 0; i < LibraryMethods.length; i++) {
+ callWhenReady(this, LibraryMethods[i]);
+ }
+
+ this.setDriver(this._config.driver);
+ }
+
+ LocalForage.prototype.INDEXEDDB = DriverType.INDEXEDDB;
+ LocalForage.prototype.LOCALSTORAGE = DriverType.LOCALSTORAGE;
+ LocalForage.prototype.WEBSQL = DriverType.WEBSQL;
+
+ // Set any config values for localForage; can be called anytime before
+ // the first API call (e.g. `getItem`, `setItem`).
+ // We loop through options so we don't overwrite existing config
+ // values.
+ LocalForage.prototype.config = function(options) {
+ // If the options argument is an object, we use it to set values.
+ // Otherwise, we return either a specified config value or all
+ // config values.
+ if (typeof(options) === 'object') {
+ // If localforage is ready and fully initialized, we can't set
+ // any new configuration values. Instead, we return an error.
+ if (this._ready) {
+ return new Error("Can't call config() after localforage " +
+ 'has been used.');
+ }
+
+ for (var i in options) {
+ if (i === 'storeName') {
+ options[i] = options[i].replace(/\W/g, '_');
+ }
+
+ this._config[i] = options[i];
+ }
+
+ // after all config options are set and
+ // the driver option is used, try setting it
+ if ('driver' in options && options.driver) {
+ this.setDriver(this._config.driver);
+ }
+
+ return true;
+ } else if (typeof(options) === 'string') {
+ return this._config[options];
+ } else {
+ return this._config;
+ }
+ };
+
+ // Used to define a custom driver, shared across all instances of
+ // localForage.
+ LocalForage.prototype.defineDriver = function(driverObject, callback,
+ errorCallback) {
+ var defineDriver = new Promise(function(resolve, reject) {
+ try {
+ var driverName = driverObject._driver;
+ var complianceError = new Error(
+ 'Custom driver not compliant; see ' +
+ 'https://mozilla.github.io/localForage/#definedriver'
+ );
+ var namingError = new Error(
+ 'Custom driver name already in use: ' + driverObject._driver
+ );
+
+ // A driver name should be defined and not overlap with the
+ // library-defined, default drivers.
+ if (!driverObject._driver) {
+ reject(complianceError);
+ return;
+ }
+ if (isLibraryDriver(driverObject._driver)) {
+ reject(namingError);
+ return;
+ }
+
+ var customDriverMethods = LibraryMethods.concat('_initStorage');
+ for (var i = 0; i < customDriverMethods.length; i++) {
+ var customDriverMethod = customDriverMethods[i];
+ if (!customDriverMethod ||
+ !driverObject[customDriverMethod] ||
+ typeof driverObject[customDriverMethod] !== 'function') {
+ reject(complianceError);
+ return;
+ }
+ }
+
+ var supportPromise = Promise.resolve(true);
+ if ('_support' in driverObject) {
+ if (driverObject._support && typeof driverObject._support === 'function') {
+ supportPromise = driverObject._support();
+ } else {
+ supportPromise = Promise.resolve(!!driverObject._support);
+ }
+ }
+
+ supportPromise.then(function(supportResult) {
+ driverSupport[driverName] = supportResult;
+ CustomDrivers[driverName] = driverObject;
+ resolve();
+ }, reject);
+ } catch (e) {
+ reject(e);
+ }
+ });
+
+ defineDriver.then(callback, errorCallback);
+ return defineDriver;
+ };
+
+ LocalForage.prototype.driver = function() {
+ return this._driver || null;
+ };
+
+ LocalForage.prototype.ready = function(callback) {
+ var self = this;
+
+ var ready = new Promise(function(resolve, reject) {
+ self._driverSet.then(function() {
+ if (self._ready === null) {
+ self._ready = self._initStorage(self._config);
+ }
+
+ self._ready.then(resolve, reject);
+ })["catch"](reject);
+ });
+
+ ready.then(callback, callback);
+ return ready;
+ };
+
+ LocalForage.prototype.setDriver = function(drivers, callback,
+ errorCallback) {
+ var self = this;
+
+ if (typeof drivers === 'string') {
+ drivers = [drivers];
+ }
+
+ this._driverSet = new Promise(function(resolve, reject) {
+ var driverName = self._getFirstSupportedDriver(drivers);
+ var error = new Error('No available storage method found.');
+
+ if (!driverName) {
+ self._driverSet = Promise.reject(error);
+ reject(error);
+ return;
+ }
+
+ self._dbInfo = null;
+ self._ready = null;
+
+ if (isLibraryDriver(driverName)) {
+ // We allow localForage to be declared as a module or as a
+ // library available without AMD/require.js.
+ if (moduleType === ModuleType.DEFINE) {
+ require([driverName], function(lib) {
+ self._extend(lib);
+
+ resolve();
+ });
+
+ return;
+ } else if (moduleType === ModuleType.EXPORT) {
+ // Making it browserify friendly
+ var driver;
+ switch (driverName) {
+ case self.INDEXEDDB:
+ driver = require('./drivers/indexeddb');
+ break;
+ case self.LOCALSTORAGE:
+ driver = require('./drivers/localstorage');
+ break;
+ case self.WEBSQL:
+ driver = require('./drivers/websql');
+ }
+
+ self._extend(driver);
+ } else {
+ self._extend(globalObject[driverName]);
+ }
+ } else if (CustomDrivers[driverName]) {
+ self._extend(CustomDrivers[driverName]);
+ } else {
+ self._driverSet = Promise.reject(error);
+ reject(error);
+ return;
+ }
+
+ resolve();
+ });
+
+ function setDriverToConfig() {
+ self._config.driver = self.driver();
+ }
+ this._driverSet.then(setDriverToConfig, setDriverToConfig);
+
+ this._driverSet.then(callback, errorCallback);
+ return this._driverSet;
+ };
+
+ LocalForage.prototype.supports = function(driverName) {
+ return !!driverSupport[driverName];
+ };
+
+ LocalForage.prototype._extend = function(libraryMethodsAndProperties) {
+ extend(this, libraryMethodsAndProperties);
+ };
+
+ // Used to determine which driver we should use as the backend for this
+ // instance of localForage.
+ LocalForage.prototype._getFirstSupportedDriver = function(drivers) {
+ if (drivers && isArray(drivers)) {
+ for (var i = 0; i < drivers.length; i++) {
+ var driver = drivers[i];
+
+ if (this.supports(driver)) {
+ return driver;
+ }
+ }
+ }
+
+ return null;
+ };
+
+ LocalForage.prototype.createInstance = function(options) {
+ return new LocalForage(options);
+ };
+
+ // The actual localForage object that we expose as a module or via a
+ // global. It's extended by pulling in one of our other libraries.
+ var localForage = new LocalForage();
+
+ // We allow localForage to be declared as a module or as a library
+ // available without AMD/require.js.
+ if (moduleType === ModuleType.DEFINE) {
+ define('localforage', function() {
+ return localForage;
+ });
+ } else if (moduleType === ModuleType.EXPORT) {
+ module.exports = localForage;
+ } else {
+ this.localforage = localForage;
+ }
+}).call(window);
diff --git a/public/editor/medium-editor/css/medium-editor-insert-plugin-frontend.min.css b/public/editor/medium-editor/css/medium-editor-insert-plugin-frontend.min.css
new file mode 100644
index 0000000..a56009f
--- /dev/null
+++ b/public/editor/medium-editor/css/medium-editor-insert-plugin-frontend.min.css
@@ -0,0 +1,10 @@
+/*!
+ * medium-editor-insert-plugin v1.6.1 - jQuery insert plugin for MediumEditor
+ *
+ * https://github.com/orthes/medium-editor-insert-plugin
+ *
+ * Copyright (c) 2014 Pavel Linkesch (http://linkesch.sk)
+ * Released under the MIT license
+ */
+
+.medium-insert-images,.mediumInsert{text-align:center}.medium-insert-images figure,.mediumInsert figure{margin:0;display:block}.medium-insert-images figure img,.mediumInsert figure img{max-width:100%;margin-top:1em;vertical-align:top}.medium-insert-images figure:first-child img,.mediumInsert figure:first-child img{margin-top:0}.medium-insert-images.medium-insert-images-left,.medium-insert-images-left.mediumInsert,.mediumInsert.small{max-width:33.33%;float:left;margin:0 30px 20px 0}.medium-insert-images.medium-insert-images-right,.medium-insert-images-right.mediumInsert{max-width:33.33%;float:right;margin:0 0 20px 30px}.medium-insert-images.medium-insert-images-grid,.medium-insert-images-grid.mediumInsert{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;margin:.5em -.5em}.medium-insert-images.medium-insert-images-grid figure,.medium-insert-images-grid.mediumInsert figure{width:33.33%;display:inline-block}.medium-insert-images.medium-insert-images-grid figure img,.medium-insert-images-grid.mediumInsert figure img{max-width:calc(100% - 1em);margin:.5em}.medium-insert-embeds,.mediumInsert-embeds{text-align:center;margin:1em 0;position:relative}.medium-insert-embeds iframe,.mediumInsert-embeds iframe,.medium-insert-embeds div,.mediumInsert-embeds div{margin:0 auto!important}.medium-insert-embeds.medium-insert-embeds-left,.medium-insert-embeds-left.mediumInsert-embeds{width:33.33%;float:left;margin:0 30px 20px 0}.medium-insert-embeds.medium-insert-embeds-right,.medium-insert-embeds-right.mediumInsert-embeds{width:33.33%;float:right;margin:0 0 20px 30px}.medium-insert-images figure,.mediumInsert figure,.medium-insert-embeds figure,.mediumInsert-embeds figure{position:relative}.medium-insert-images figure figcaption,.mediumInsert figure figcaption,.medium-insert-embeds figure figcaption,.mediumInsert-embeds figure figcaption{position:relative;z-index:1;display:block;text-align:center;margin:10px 0;color:#ccc;font-size:.8em;font-style:italic;outline:0 solid transparent}.medium-insert-images figure figcaption:focus,.mediumInsert figure figcaption:focus,.medium-insert-embeds figure figcaption:focus,.mediumInsert-embeds figure figcaption:focus{outline:0 solid transparent}
\ No newline at end of file
diff --git a/public/editor/medium-editor/css/medium-editor-insert-plugin.min.css b/public/editor/medium-editor/css/medium-editor-insert-plugin.min.css
new file mode 100644
index 0000000..71624a9
--- /dev/null
+++ b/public/editor/medium-editor/css/medium-editor-insert-plugin.min.css
@@ -0,0 +1,10 @@
+/*!
+ * medium-editor-insert-plugin v1.6.1 - jQuery insert plugin for MediumEditor
+ *
+ * https://github.com/orthes/medium-editor-insert-plugin
+ *
+ * Copyright (c) 2014 Pavel Linkesch (http://linkesch.sk)
+ * Released under the MIT license
+ */
+
+.medium-insert-images,.mediumInsert{text-align:center}.medium-insert-images figure,.mediumInsert figure{margin:0;display:block}.medium-insert-images figure img,.mediumInsert figure img{max-width:100%;margin-top:1em;vertical-align:top}.medium-insert-images figure:first-child img,.mediumInsert figure:first-child img{margin-top:0}.medium-insert-images.medium-insert-images-left,.medium-insert-images-left.mediumInsert,.mediumInsert.small{max-width:33.33%;float:left;margin:0 30px 20px 0}.medium-insert-images.medium-insert-images-right,.medium-insert-images-right.mediumInsert{max-width:33.33%;float:right;margin:0 0 20px 30px}.medium-insert-images.medium-insert-images-grid,.medium-insert-images-grid.mediumInsert{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-align:start;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;margin:.5em -.5em}.medium-insert-images.medium-insert-images-grid figure,.medium-insert-images-grid.mediumInsert figure{width:33.33%;display:inline-block}.medium-insert-images.medium-insert-images-grid figure img,.medium-insert-images-grid.mediumInsert figure img{max-width:calc(100% - 1em);margin:.5em}.medium-insert-embeds,.mediumInsert-embeds{text-align:center;margin:1em 0;position:relative}.medium-insert-embeds iframe,.mediumInsert-embeds iframe,.medium-insert-embeds div,.mediumInsert-embeds div{margin:0 auto!important}.medium-insert-embeds.medium-insert-embeds-left,.medium-insert-embeds-left.mediumInsert-embeds{width:33.33%;float:left;margin:0 30px 20px 0}.medium-insert-embeds.medium-insert-embeds-right,.medium-insert-embeds-right.mediumInsert-embeds{width:33.33%;float:right;margin:0 0 20px 30px}.medium-insert-images figure,.mediumInsert figure,.medium-insert-embeds figure,.mediumInsert-embeds figure{position:relative}.medium-insert-images figure figcaption,.mediumInsert figure figcaption,.medium-insert-embeds figure figcaption,.mediumInsert-embeds figure figcaption{position:relative;z-index:1;display:block;text-align:center;margin:10px 0;color:#ccc;font-size:.8em;font-style:italic;outline:0 solid transparent}.medium-insert-images figure figcaption:focus,.mediumInsert figure figcaption:focus,.medium-insert-embeds figure figcaption:focus,.mediumInsert-embeds figure figcaption:focus{outline:0 solid transparent}.medium-editor-insert-plugin{outline:0 solid transparent}.medium-editor-insert-plugin:focus{outline:0 solid transparent}.medium-editor-insert-plugin .clearfix:before,.medium-editor-insert-plugin:before,.medium-editor-insert-plugin .clearfix:after,.medium-editor-insert-plugin:after{content:" ";display:table;clear:both}.medium-editor-insert-plugin p{margin:1em 0}.medium-editor-insert-plugin progress{display:block;margin:1em auto}.medium-editor-insert-plugin .hide{display:none}.medium-editor-insert-plugin.medium-editor-placeholder:after{padding:1em 0}.medium-editor-insert-plugin .medium-insert-buttons{position:absolute;color:#ddd;font-size:.9em}.medium-editor-insert-plugin .medium-insert-buttons a{text-decoration:underline;cursor:pointer}.medium-editor-insert-plugin .medium-insert-buttons .medium-insert-buttons-show{box-sizing:border-box;display:block;width:32px;height:32px;margin-top:-5px;border-radius:20px;border:1px solid;font-size:25px;line-height:28px;text-align:center;text-decoration:none}.medium-editor-insert-plugin .medium-insert-buttons .medium-insert-buttons-addons{margin:0;padding:0;list-style:none;display:none;position:relative;z-index:2;left:55px;top:-32px}.medium-editor-insert-plugin .medium-insert-buttons .medium-insert-buttons-addons li{display:inline-block}.medium-editor-insert-plugin .medium-insert-buttons .medium-insert-buttons-addons li a{box-sizing:border-box;display:inline-block;margin:0 5px;width:32px;height:32px;border-radius:20px;border:1px solid;font-size:20px;line-height:28px;text-align:center}.medium-editor-insert-plugin .medium-insert-buttons .medium-insert-buttons-addons li a .fa{font-size:15px}.medium-insert-caption-placeholder{position:relative}.medium-insert-caption-placeholder:after{position:absolute;top:0;left:0;width:100%;text-align:center;content:attr(data-placeholder)}.dragging{cursor:move}.medium-insert-image-active{outline:2px solid #000}.medium-insert-images-toolbar{display:none}.medium-insert-images,.mediumInsert{margin:1em 0}.medium-insert-images .dragged,.mediumInsert .dragged{position:absolute;top:0;opacity:.5;z-index:2000}.medium-insert-images .placeholder,.mediumInsert .placeholder{position:relative;margin:0;padding:0;border:none}.medium-insert-images .medium-insert-images-progress,.mediumInsert .medium-insert-images-progress{position:absolute;width:100%;height:100%;top:0;right:0;background:rgba(255,255,255,.4)}.medium-insert-embeds-input{position:relative;color:#ccc;z-index:1;text-align:left}.medium-insert-embeds-placeholder{position:relative}.medium-insert-embeds-placeholder:after{position:absolute;top:0;left:0;content:attr(data-placeholder);color:#ccc}.medium-insert-embeds-selected .medium-insert-embed{outline:2px solid #000}.medium-insert-embeds-toolbar{display:none}.medium-insert-embeds .medium-insert-embeds-overlay,.mediumInsert-embeds .medium-insert-embeds-overlay{position:absolute;width:100%;height:100%;top:0;left:0}
\ No newline at end of file
diff --git a/public/editor/medium-editor/css/medium-editor.min.css b/public/editor/medium-editor/css/medium-editor.min.css
new file mode 100644
index 0000000..935717c
--- /dev/null
+++ b/public/editor/medium-editor/css/medium-editor.min.css
@@ -0,0 +1 @@
+.clearfix:after{display:block;visibility:hidden;clear:both;height:0;content:" ";font-size:0}@-webkit-keyframes pop-upwards{0%{-webkit-transform:matrix(.97,0,0,1,0,12);transform:matrix(.97,0,0,1,0,12);opacity:0}20%{-webkit-transform:matrix(.99,0,0,1,0,2);transform:matrix(.99,0,0,1,0,2);opacity:.7}40%{-webkit-transform:matrix(1,0,0,1,0,-1);transform:matrix(1,0,0,1,0,-1);opacity:1}100%,70%{-webkit-transform:matrix(1,0,0,1,0,0);transform:matrix(1,0,0,1,0,0);opacity:1}}@keyframes pop-upwards{0%{-webkit-transform:matrix(.97,0,0,1,0,12);transform:matrix(.97,0,0,1,0,12);opacity:0}20%{-webkit-transform:matrix(.99,0,0,1,0,2);transform:matrix(.99,0,0,1,0,2);opacity:.7}40%{-webkit-transform:matrix(1,0,0,1,0,-1);transform:matrix(1,0,0,1,0,-1);opacity:1}100%,70%{-webkit-transform:matrix(1,0,0,1,0,0);transform:matrix(1,0,0,1,0,0);opacity:1}}.data-medium-element sup{vertical-align:super}.data-medium-element sub{vertical-align:sub}.data-medium-element img{max-width:100%}.medium-editor-hidden{display:none}.medium-toolbar-arrow-over:before,.medium-toolbar-arrow-under:after{position:absolute;left:50%;display:block;margin-left:-8px;width:0;height:0;border-style:solid;content:""}.medium-toolbar-arrow-under:after{border-width:8px 8px 0}.medium-toolbar-arrow-over:before{top:-8px;border-width:0 8px 8px}.medium-editor-anchor-preview,.medium-editor-toolbar{position:absolute;top:0;left:0;z-index:2000;visibility:hidden;font-size:16px;font-family:HelveticaNeue,Helvetica,Arial,sans-serif}.medium-editor-anchor-preview ul,.medium-editor-toolbar ul{margin:0;padding:0}.medium-editor-anchor-preview li,.medium-editor-toolbar li{float:left;margin:0;padding:0;list-style:none}.medium-editor-anchor-preview li button,.medium-editor-toolbar li button{display:block;margin:0;padding:15px;cursor:pointer;font-size:14px;line-height:1.33;text-decoration:none;box-sizing:border-box}.medium-editor-anchor-preview li button:focus,.medium-editor-toolbar li button:focus{outline:0}.medium-editor-anchor-preview li .medium-editor-action-underline,.medium-editor-toolbar li .medium-editor-action-underline{text-decoration:underline}.medium-editor-anchor-preview li .medium-editor-action-pre,.medium-editor-toolbar li .medium-editor-action-pre{padding:15px 0;font-weight:100;font-size:12px;font-family:Menlo,monospace}.medium-editor-anchor-preview{max-width:280px;word-break:break-all;word-wrap:break-word;text-align:center;line-height:1.4}.medium-editor-anchor-preview a{display:inline-block;margin:5px 5px 5px 10px;color:#fff}.medium-editor-anchor-preview-active,.medium-editor-toolbar-active{visibility:visible}.sticky-toolbar{position:fixed;top:1px}.medium-editor-toolbar-active.stalker-toolbar{-webkit-animation:pop-upwards 160ms forwards linear;animation:pop-upwards 160ms forwards linear}.medium-editor-action-bold{font-weight:bolder}.medium-editor-action-italic{font-style:italic}.medium-editor-toolbar-form{display:none}.medium-editor-toolbar-form a,.medium-editor-toolbar-form input{font-family:HelveticaNeue,Helvetica,Arial,sans-serif}.medium-editor-toolbar-form .medium-editor-toolbar-input,.medium-editor-toolbar-form label{margin:0;padding:6px;width:316px;border:none;font-size:14px;box-sizing:border-box}.medium-editor-toolbar-form .medium-editor-toolbar-input:focus,.medium-editor-toolbar-form label:focus{outline:0;border:none;box-shadow:none;appearance:none}.medium-editor-toolbar-form label{display:block}.medium-editor-toolbar-form a{display:inline-block;margin:0 10px;text-decoration:none;font-weight:bolder;font-size:24px}.medium-editor-placeholder{position:relative}.medium-editor-placeholder:after{position:absolute;top:0;left:0;content:attr(data-placeholder)!important;font-style:italic;white-space:pre}.medium-editor-dragover{background:#ddd}.medium-image-loading{width:40px;height:40px;background-color:#333;display:inline-block;border-radius:100%;-webkit-animation:medium-image-loading-animation 1s infinite ease-in-out;animation:medium-image-loading-animation 1s infinite ease-in-out}@-webkit-keyframes medium-image-loading-animation{0%{-webkit-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);transform:scale(1);opacity:0}}@keyframes medium-image-loading-animation{0%{-webkit-transform:scale(0);transform:scale(0)}100%{-webkit-transform:scale(1);transform:scale(1);opacity:0}}
\ No newline at end of file
diff --git a/public/editor/medium-editor/css/themes/bootstrap.min.css b/public/editor/medium-editor/css/themes/bootstrap.min.css
new file mode 100755
index 0000000..18bb6aa
--- /dev/null
+++ b/public/editor/medium-editor/css/themes/bootstrap.min.css
@@ -0,0 +1 @@
+.medium-toolbar-arrow-under:after{top:60px;border-color:#428bca transparent transparent}.medium-toolbar-arrow-over:before{border-color:transparent transparent #428bca}.medium-editor-toolbar{border:1px solid #357ebd;background-color:#428bca;border-radius:4px}.medium-editor-toolbar li button{min-width:60px;height:60px;border:none;border-right:1px solid #357ebd;background-color:transparent;color:#fff;box-sizing:border-box;-webkit-transition:background-color .2s ease-in,color .2s ease-in;transition:background-color .2s ease-in,color .2s ease-in}.medium-editor-toolbar li button:hover{background-color:#3276b1;color:#fff}.medium-editor-toolbar li .medium-editor-button-first{border-top-left-radius:4px;border-bottom-left-radius:4px}.medium-editor-toolbar li .medium-editor-button-last{border-right:none;border-top-right-radius:4px;border-bottom-right-radius:4px}.medium-editor-toolbar li .medium-editor-button-active{background-color:#3276b1;color:#fff}.medium-editor-toolbar-form{background:#428bca;color:#fff;border-radius:4px}.medium-editor-toolbar-form .medium-editor-toolbar-input{height:60px;background:#428bca;color:#fff}.medium-editor-toolbar-form .medium-editor-toolbar-input::-webkit-input-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form .medium-editor-toolbar-input:-moz-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form .medium-editor-toolbar-input::-moz-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form .medium-editor-toolbar-input:-ms-input-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form a{color:#fff}.medium-editor-toolbar-anchor-preview{background:#428bca;color:#fff;border-radius:4px}.medium-editor-placeholder:after{color:#357ebd}
\ No newline at end of file
diff --git a/public/editor/medium-editor/css/themes/default.min.css b/public/editor/medium-editor/css/themes/default.min.css
new file mode 100755
index 0000000..06c5ba8
--- /dev/null
+++ b/public/editor/medium-editor/css/themes/default.min.css
@@ -0,0 +1 @@
+.medium-toolbar-arrow-under:after{top:50px;border-color:#242424 transparent transparent}.medium-toolbar-arrow-over:before{top:-8px;border-color:transparent transparent #242424}.medium-editor-toolbar{border:1px solid #000;background:-webkit-linear-gradient(top,#242424,rgba(36,36,36,.75));background:linear-gradient(to bottom,#242424,rgba(36,36,36,.75));border-radius:5px;box-shadow:0 0 3px #000}.medium-editor-toolbar li button{min-width:50px;height:50px;border:0;border-right:1px solid #000;border-left:1px solid #333;border-left:1px solid rgba(255,255,255,.1);color:#fff;background:-webkit-linear-gradient(top,#242424,rgba(36,36,36,.89));background:linear-gradient(to bottom,#242424,rgba(36,36,36,.89));box-shadow:0 2px 2px rgba(0,0,0,.3);-webkit-transition:background-color .2s ease-in;transition:background-color .2s ease-in}.medium-editor-toolbar li button:hover{background-color:#000;color:#ff0}.medium-editor-toolbar li .medium-editor-button-first{border-top-left-radius:5px;border-bottom-left-radius:5px}.medium-editor-toolbar li .medium-editor-button-last{border-top-right-radius:5px;border-bottom-right-radius:5px}.medium-editor-toolbar li .medium-editor-button-active{color:#fff;background:-webkit-linear-gradient(top,#242424,rgba(0,0,0,.89));background:linear-gradient(to bottom,#242424,rgba(0,0,0,.89))}.medium-editor-toolbar-form{background:#242424;color:#999;border-radius:5px}.medium-editor-toolbar-form .medium-editor-toolbar-input{height:50px;background:#242424;color:#ccc;box-sizing:border-box}.medium-editor-toolbar-form a{color:#fff}.medium-editor-toolbar-anchor-preview{background:#242424;color:#fff;border-radius:5px}.medium-editor-placeholder:after{color:#b3b3b1}
\ No newline at end of file
diff --git a/public/editor/medium-editor/css/themes/flat.min.css b/public/editor/medium-editor/css/themes/flat.min.css
new file mode 100755
index 0000000..241b580
--- /dev/null
+++ b/public/editor/medium-editor/css/themes/flat.min.css
@@ -0,0 +1 @@
+.medium-toolbar-arrow-under:after{top:60px;border-color:#57ad68 transparent transparent}.medium-toolbar-arrow-over:before{top:-8px;border-color:transparent transparent #57ad68}.medium-editor-toolbar{background-color:#57ad68}.medium-editor-toolbar li{padding:0}.medium-editor-toolbar li button{min-width:60px;height:60px;border:none;border-right:1px solid #9ccea6;background-color:transparent;color:#fff;-webkit-transition:background-color .2s ease-in,color .2s ease-in;transition:background-color .2s ease-in,color .2s ease-in}.medium-editor-toolbar li button:hover{background-color:#346a3f;color:#fff}.medium-editor-toolbar li .medium-editor-button-active{background-color:#23482a;color:#fff}.medium-editor-toolbar li .medium-editor-button-last{border-right:none}.medium-editor-toolbar-form .medium-editor-toolbar-input{height:60px;background:#57ad68;color:#fff}.medium-editor-toolbar-form .medium-editor-toolbar-input::-webkit-input-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form .medium-editor-toolbar-input:-moz-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form .medium-editor-toolbar-input::-moz-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form .medium-editor-toolbar-input:-ms-input-placeholder{color:#fff;color:rgba(255,255,255,.8)}.medium-editor-toolbar-form a{color:#fff}.medium-editor-toolbar-anchor-preview{background:#57ad68;color:#fff}.medium-editor-placeholder:after{color:#fff}
\ No newline at end of file
diff --git a/public/editor/medium-editor/css/themes/mani.min.css b/public/editor/medium-editor/css/themes/mani.min.css
new file mode 100755
index 0000000..57d2de5
--- /dev/null
+++ b/public/editor/medium-editor/css/themes/mani.min.css
@@ -0,0 +1 @@
+.medium-toolbar-arrow-over:before,.medium-toolbar-arrow-under:after{display:none}.medium-editor-toolbar{border:1px solid #cdd6e0;background:-webkit-linear-gradient(bottom,#dee7f0,#fff);background:linear-gradient(to top,#dee7f0,#fff);border-radius:2px;box-shadow:0 2px 6px rgba(0,0,0,.45)}.medium-editor-toolbar li button{min-width:50px;height:50px;border:none;border-right:1px solid #cdd6e0;background-color:transparent;color:#40648a;-webkit-transition:background-color .2s ease-in,color .2s ease-in;transition:background-color .2s ease-in,color .2s ease-in}.medium-editor-toolbar li button:hover{background-color:#5c90c7;background-color:rgba(92,144,199,.45);color:#fff}.medium-editor-toolbar li .medium-editor-button-first{border-top-left-radius:2px;border-bottom-left-radius:2px}.medium-editor-toolbar li .medium-editor-button-last{border-top-right-radius:2px;border-bottom-right-radius:2px}.medium-editor-toolbar li .medium-editor-button-active{color:#000;background:-webkit-linear-gradient(top,#dee7f0,rgba(0,0,0,.1));background:linear-gradient(to bottom,#dee7f0,rgba(0,0,0,.1))}.medium-editor-toolbar-form{background:#dee7f0;color:#999;border-radius:2px}.medium-editor-toolbar-form .medium-editor-toolbar-input{height:50px;background:#dee7f0;color:#40648a;box-sizing:border-box}.medium-editor-toolbar-form a{color:#40648a}.medium-editor-toolbar-anchor-preview{background:#dee7f0;color:#40648a;border-radius:2px}.medium-editor-placeholder:after{color:#cdd6e0}
\ No newline at end of file
diff --git a/public/editor/medium-editor/css/themes/roman.min.css b/public/editor/medium-editor/css/themes/roman.min.css
new file mode 100755
index 0000000..da1e706
--- /dev/null
+++ b/public/editor/medium-editor/css/themes/roman.min.css
@@ -0,0 +1 @@
+.medium-toolbar-arrow-over:before,.medium-toolbar-arrow-under:after{display:none}.medium-editor-toolbar{background-color:#fff;background-color:rgba(255,255,255,.95);border-radius:5px;box-shadow:0 2px 6px rgba(0,0,0,.45)}.medium-editor-toolbar li button{min-width:50px;height:50px;border:none;border-right:1px solid #a8a8a8;color:#889aac;box-shadow:inset 0 0 3px #f8f8e6;background:-webkit-linear-gradient(top,#fff,rgba(0,0,0,.2));background:linear-gradient(to bottom,#fff,rgba(0,0,0,.2));text-shadow:1px 4px 6px #def,0 0 0 #000,1px 4px 6px #def;-webkit-transition:background-color .2s ease-in;transition:background-color .2s ease-in}.medium-editor-toolbar li button:hover{background-color:#fff;color:#fff;color:rgba(0,0,0,.8)}.medium-editor-toolbar li .medium-editor-button-first{border-top-left-radius:5px;border-bottom-left-radius:5px}.medium-editor-toolbar li .medium-editor-button-last{border-top-right-radius:5px;border-bottom-right-radius:5px}.medium-editor-toolbar li .medium-editor-button-active{color:#000;color:rgba(0,0,0,.8);background:-webkit-linear-gradient(bottom,#fff,rgba(0,0,0,.1));background:linear-gradient(to top,#fff,rgba(0,0,0,.1))}.medium-editor-toolbar-form{background:#fff;color:#999;border-radius:5px}.medium-editor-toolbar-form .medium-editor-toolbar-input{margin:0;height:50px;background:#fff;color:#a8a8a8}.medium-editor-toolbar-form a{color:#889aac}.medium-editor-toolbar-anchor-preview{background:#fff;color:#889aac;border-radius:5px}.medium-editor-placeholder:after{color:#a8a8a8}
\ No newline at end of file
diff --git a/public/editor/medium-editor/js/medium-editor-insert-plugin.min.js b/public/editor/medium-editor/js/medium-editor-insert-plugin.min.js
new file mode 100644
index 0000000..15f1767
--- /dev/null
+++ b/public/editor/medium-editor/js/medium-editor-insert-plugin.min.js
@@ -0,0 +1,11 @@
+/*!
+ * medium-editor-insert-plugin v1.6.1 - jQuery insert plugin for MediumEditor
+ *
+ * https://github.com/orthes/medium-editor-insert-plugin
+ *
+ * Copyright (c) 2014 Pavel Linkesch (http://linkesch.sk)
+ * Released under the MIT license
+ */
+
+this.MediumInsert=this.MediumInsert||{},this.MediumInsert.Templates=this.MediumInsert.Templates||{},this.MediumInsert.Templates["src/js/templates/core-buttons.hbs"]=Handlebars.template({1:function(a,b,c,d){var e,f,g=this.lambda,h=this.escapeExpression,i="function",j=b.helperMissing,k=' ';return f=null!=(f=b.label||(null!=a?a.label:a))?f:j,e=typeof f===i?f.call(a,{name:"label",hash:{},data:d}):f,null!=e&&(k+=e),k+" \n"},compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f='\n"},useData:!0}),this.MediumInsert.Templates["src/js/templates/core-caption.hbs"]=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f="function",g=b.helperMissing,h=this.escapeExpression;return' '},useData:!0}),this.MediumInsert.Templates["src/js/templates/core-empty-line.hbs"]=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){return"
\n"},useData:!0}),this.MediumInsert.Templates["src/js/templates/embeds-toolbar.hbs"]=Handlebars.template({1:function(a,b,c,d){var e,f=' \n"},2:function(a,b,c,d){var e,f="";return e=b["if"].call(a,null!=a?a.label:a,{name:"if",hash:{},fn:this.program(3,d),inverse:this.noop,data:d}),null!=e&&(f+=e),f},3:function(a,b,c,d){var e,f,g=this.lambda,h=this.escapeExpression,i="function",j=b.helperMissing,k=' \n ';return f=null!=(f=b.label||(null!=a?a.label:a))?f:j,e=typeof f===i?f.call(a,{name:"label",hash:{},data:d}):f,null!=e&&(k+=e),k+" \n \n"},5:function(a,b,c,d){var e,f=' \n"},compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f="";return e=b["if"].call(a,null!=a?a.styles:a,{name:"if",hash:{},fn:this.program(1,d),inverse:this.noop,data:d}),null!=e&&(f+=e),f+="\n",e=b["if"].call(a,null!=a?a.actions:a,{name:"if",hash:{},fn:this.program(5,d),inverse:this.noop,data:d}),null!=e&&(f+=e),f},useData:!0}),this.MediumInsert.Templates["src/js/templates/embeds-wrapper.hbs"]=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f,g="function",h=b.helperMissing,i='\n
\n \n ';return f=null!=(f=b.html||(null!=a?a.html:a))?f:h,e=typeof f===g?f.call(a,{name:"html",hash:{},data:d}):f,null!=e&&(i+=e),i+'\n
\n \n
\n
'},useData:!0}),this.MediumInsert.Templates["src/js/templates/images-fileupload.hbs"]=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){return' '},useData:!0}),this.MediumInsert.Templates["src/js/templates/images-image.hbs"]=Handlebars.template({1:function(a,b,c,d){return'
\n'},compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f,g="function",h=b.helperMissing,i=this.escapeExpression,j='\n \n';return e=b["if"].call(a,null!=a?a.progress:a,{name:"if",hash:{},fn:this.program(1,d),inverse:this.noop,data:d}),null!=e&&(j+=e),j+" "},useData:!0}),this.MediumInsert.Templates["src/js/templates/images-progressbar.hbs"]=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){return'0 '},useData:!0}),this.MediumInsert.Templates["src/js/templates/images-toolbar.hbs"]=Handlebars.template({1:function(a,b,c,d){var e,f="";return e=b["if"].call(a,null!=a?a.label:a,{name:"if",hash:{},fn:this.program(2,d),inverse:this.noop,data:d}),null!=e&&(f+=e),f},2:function(a,b,c,d){var e,f,g=this.lambda,h=this.escapeExpression,i="function",j=b.helperMissing,k=' \n ';return f=null!=(f=b.label||(null!=a?a.label:a))?f:j,e=typeof f===i?f.call(a,{name:"label",hash:{},data:d}):f,null!=e&&(k+=e),k+" \n \n"},4:function(a,b,c,d){var e,f=' \n"},5:function(a,b,c,d){var e,f="";return e=b["if"].call(a,null!=a?a.label:a,{name:"if",hash:{},fn:this.program(6,d),inverse:this.noop,data:d}),null!=e&&(f+=e),f},6:function(a,b,c,d){var e,f,g=this.lambda,h=this.escapeExpression,i="function",j=b.helperMissing,k=' \n ';return f=null!=(f=b.label||(null!=a?a.label:a))?f:j,e=typeof f===i?f.call(a,{name:"label",hash:{},data:d}):f,null!=e&&(k+=e),k+" \n \n"},compiler:[6,">= 2.0.0-beta.1"],main:function(a,b,c,d){var e,f='\n\n",e=b["if"].call(a,null!=a?a.actions:a,{name:"if",hash:{},fn:this.program(4,d),inverse:this.noop,data:d}),null!=e&&(f+=e),f},useData:!0}),function(a,b,c,d){"use strict";function e(a){return a.charAt(0).toUpperCase()+a.slice(1)}function f(c,d){var e;this.el=c,this.$el=a(c),this.templates=b.MediumInsert.Templates,d&&(e=d.editor,d.editor=null),this.options=a.extend(!0,{},h,d),this.options.editor=e,this._defaults=h,this._name=g,this.options&&this.options.editor&&(this.options.editor._deactivate=this.options.editor.deactivate,this.options.editor._activate=this.options.editor.activate,this.options.editor.deactivate=this.editorDeactivate,this.options.editor.activate=this.editorActivate,this.options.editor._serialize=this.options.editor.serialize,this.options.editor._destroy=this.options.editor.destroy,this.options.editor._setup=this.options.editor.setup,this.options.editor._hideInsertButtons=this.hideButtons,this.options.editor.serialize=this.editorSerialize,this.options.editor.destroy=this.editorDestroy,this.options.editor.setup=this.editorSetup,this.options.editor.placeholders.updatePlaceholder=this.editorUpdatePlaceholder)}var g="mediumInsert",h={editor:null,enabled:!0,addons:{images:!0,embeds:!0}};f.prototype.init=function(){this.$el.addClass("medium-editor-insert-plugin"),("object"!=typeof this.options.addons||0===Object.keys(this.options.addons).length)&&this.disable(),this.initAddons(),this.clean(),this.events()},f.prototype.events=function(){var c=this;this.$el.on("dragover drop",function(a){a.preventDefault()}).on("keyup click",a.proxy(this,"toggleButtons")).on("selectstart mousedown",".medium-insert, .medium-insert-buttons",a.proxy(this,"disableSelection")).on("click",".medium-insert-buttons-show",a.proxy(this,"toggleAddons")).on("click",".medium-insert-action",a.proxy(this,"addonAction")).on("paste",".medium-insert-caption-placeholder",function(b){a.proxy(c,"removeCaptionPlaceholder")(a(b.target))}),a(b).on("resize",a.proxy(this,"positionButtons",null))},f.prototype.getEditor=function(){return this.options.editor},f.prototype.editorSerialize=function(){var b=this._serialize();return a.each(b,function(c){var d=a("
").html(b[c].value);d.find(".medium-insert-buttons").remove(),b[c].value=d.html()}),b},f.prototype.editorDeactivate=function(){a.each(this.elements,function(b,c){a(c).data("plugin_"+g).disable()}),this._deactivate()},f.prototype.editorActivate=function(){this._activate(),a.each(this.elements,function(b,c){a(c).data("plugin_"+g).enable()})},f.prototype.editorDestroy=function(){a.each(this.elements,function(b,c){a(c).data("plugin_"+g).disable()}),this._destroy()},f.prototype.editorSetup=function(){this._setup(),a.each(this.elements,function(b,c){a(c).data("plugin_"+g).enable()})},f.prototype.editorUpdatePlaceholder=function(b){var c,d=a(b).clone();d.find(".medium-insert-buttons").remove(),c=d.html().replace(/^\s+|\s+$/g,"").replace(/^ <\/p>$/,""),b.querySelector("img")||b.querySelector("blockquote")||""!==c?this.hidePlaceholder(b):(this.showPlaceholder(b),this.base._hideInsertButtons(a(b)))},f.prototype.deselect=function(){c.getSelection().removeAllRanges()},f.prototype.disable=function(){this.options.enabled=!1,this.$el.find(".medium-insert-buttons").addClass("hide")},f.prototype.enable=function(){this.options.enabled=!0,this.$el.find(".medium-insert-buttons").removeClass("hide")},f.prototype.disableSelection=function(b){var c=a(b.target);(c.is("img")===!1||c.hasClass("medium-insert-buttons-show"))&&b.preventDefault()},f.prototype.initAddons=function(){var b=this;this.options.addons&&0!==this.options.addons.length&&a.each(this.options.addons,function(a,c){var d=g+e(a);return c===!1?void delete b.options.addons[a]:(b.$el[d](c),void(b.options.addons[a]=b.$el.data("plugin_"+d).options))})},f.prototype.clean=function(){var b,c,d,e=this;this.options.enabled!==!1&&((""===this.$el.html().trim()||" "===this.$el.html().trim())&&this.$el.html(this.templates["src/js/templates/core-empty-line.hbs"]().trim()),d=this.$el.contents().filter(function(){return"#text"===this.nodeName&&""!==a.trim(a(this).text())}),d.each(function(){a(this).wrap("
"),e.moveCaret(a(this).parent(),a(this).text().length)}),this.addButtons(),b=this.$el.find(".medium-insert-buttons"),c=b.prev(),c.attr("class")&&c.attr("class").match(/medium\-insert(?!\-active)/)&&b.before(this.templates["src/js/templates/core-empty-line.hbs"]().trim()))},f.prototype.getButtons=function(){return this.options.enabled!==!1?this.templates["src/js/templates/core-buttons.hbs"]({addons:this.options.addons}).trim():void 0},f.prototype.addButtons=function(){0===this.$el.find(".medium-insert-buttons").length&&this.$el.append(this.getButtons())},f.prototype.toggleButtons=function(c){var d,e,f,g,h=a(c.target),i=b.getSelection(),j=this;this.options.enabled!==!1&&(i&&0!==i.rangeCount?(d=i.getRangeAt(0),e=a(d.commonAncestorContainer)):e=h,e.hasClass("medium-editor-insert-plugin")&&(e=e.find("p:first")),f=e.is("p")?e:e.closest("p"),this.clean(),h.hasClass("medium-editor-placeholder")===!1&&0===h.closest(".medium-insert-buttons").length&&0===e.closest(".medium-insert-buttons").length&&(this.$el.find(".medium-insert-active").removeClass("medium-insert-active"),a.each(this.options.addons,function(a){return h.closest(".medium-insert-"+a).length&&(e=h),e.closest(".medium-insert-"+a).length?(f=e.closest(".medium-insert-"+a),void(g=a)):void 0}),f.length&&(""===f.text().trim()&&!g||"images"===g)?(f.addClass("medium-insert-active"),setTimeout(function(){j.positionButtons(g),j.showButtons(g)},g?100:0)):this.hideButtons()))},f.prototype.showButtons=function(a){var b=this.$el.find(".medium-insert-buttons");b.show(),b.find("li").show(),a&&(b.find("li").hide(),b.find('a[data-addon="'+a+'"]').parent().show())},f.prototype.hideButtons=function(a){a=a||this.$el,a.find(".medium-insert-buttons").hide(),a.find(".medium-insert-buttons-addons").hide()},f.prototype.positionButtons=function(a){var b,c,d=this.$el.find(".medium-insert-buttons"),e=this.$el.find(".medium-insert-active"),f=e.find("figure:first").length?e.find("figure:first"):e;e.length&&(b=e.position().left-parseInt(d.find(".medium-insert-buttons-addons").css("left"),10)-parseInt(d.find(".medium-insert-buttons-addons a:first").css("margin-left"),10),b=0>b?e.position().left:b,c=e.position().top+parseInt(e.css("margin-top"),10),a&&(e.position().left!==f.position().left&&(b=f.position().left),c+=e.height()+15),d.css({left:b,top:c}))},f.prototype.toggleAddons=function(){this.$el.find(".medium-insert-buttons-addons").toggle()},f.prototype.hideAddons=function(){this.$el.find(".medium-insert-buttons-addons").hide()},f.prototype.addonAction=function(b){var c=a(b.target).is("a")?a(b.target):a(b.target).closest("a"),d=c.data("addon"),f=c.data("action");this.$el.data("plugin_"+g+e(d))[f]()},f.prototype.moveCaret=function(a,d){var e,f,g;if(d=d||0,e=c.createRange(),f=b.getSelection(),g=a.get(0),!g.childNodes.length){var h=c.createTextNode(" ");g.appendChild(h)}e.setStart(g.childNodes[0],d),e.collapse(!0),f.removeAllRanges(),f.addRange(e)},f.prototype.addCaption=function(a,b){var c=a.find("figcaption");0===c.length&&a.append(this.templates["src/js/templates/core-caption.hbs"]({placeholder:b}))},f.prototype.removeCaptions=function(b){var c=this.$el.find("figcaption");b&&(c=c.not(b)),c.each(function(){(a(this).hasClass("medium-insert-caption-placeholder")||""===a(this).text().trim())&&a(this).remove()})},f.prototype.removeCaptionPlaceholder=function(a){var b=a.is("figcaption")?a:a.find("figcaption");b.length&&b.removeClass("medium-insert-caption-placeholder").removeAttr("data-placeholder")},f.prototype.deprecated=function(a,c,e){var f=a+" is deprecated, please use "+c+" instead.";e&&(f+=" Will be removed in "+e),b.console!==d&&b.console.warn(f)},a.fn[g]=function(b){return this.each(function(){a.data(this,"plugin_"+g)?"string"==typeof b&&a.data(this,"plugin_"+g)[b]&&a.data(this,"plugin_"+g)[b]():(a.data(this,"plugin_"+g,new f(this,b)),a.data(this,"plugin_"+g).init())})}}(jQuery,window,document),function(a,b,c,d){"use strict";function e(c,d){this.el=c,this.$el=a(c),this.templates=b.MediumInsert.Templates,this.core=this.$el.data("plugin_"+f),this.options=a.extend(!0,{},h,d),this._defaults=h,this._name=f,this.core.getEditor()&&(this.core.getEditor()._serializePreEmbeds=this.core.getEditor().serialize,this.core.getEditor().serialize=this.editorSerialize),this.init()}var f="mediumInsert",g="Embeds",h={label:' ',placeholder:"Paste a YouTube, Vimeo, Facebook, Twitter or Instagram link and press Enter",oembedProxy:"http://medium.iframe.ly/api/oembed?iframe=1",captions:!0,captionPlaceholder:"Type caption (optional)",styles:{wide:{label:' '},left:{label:' '},right:{label:' '}},actions:{remove:{label:' ',clicked:function(){var b=a.Event("keydown");b.which=8,a(c).trigger(b)}}}};e.prototype.init=function(){var b=this.$el.find(".medium-insert-embeds");b.attr("contenteditable",!1),b.each(function(){0===a(this).find(".medium-insert-embeds-overlay").length&&a(this).append(a("
").addClass("medium-insert-embeds-overlay"))}),this.events(),this.backwardsCompatibility()},e.prototype.events=function(){a(c).on("click",a.proxy(this,"unselectEmbed")).on("keydown",a.proxy(this,"removeEmbed")).on("click",".medium-insert-embeds-toolbar .medium-editor-action",a.proxy(this,"toolbarAction")).on("click",".medium-insert-embeds-toolbar2 .medium-editor-action",a.proxy(this,"toolbar2Action")),this.$el.on("keyup click paste",a.proxy(this,"togglePlaceholder")).on("keydown",a.proxy(this,"processLink")).on("click",".medium-insert-embeds-overlay",a.proxy(this,"selectEmbed")).on("contextmenu",".medium-insert-embeds-placeholder",a.proxy(this,"fixRightClickOnPlaceholder"))},e.prototype.backwardsCompatibility=function(){var b=this;this.$el.find(".mediumInsert-embeds").removeClass("mediumInsert-embeds").addClass("medium-insert-embeds"),this.$el.find(".medium-insert-embeds").each(function(){0===a(this).find(".medium-insert-embed").length&&(a(this).after(b.templates["src/js/templates/embeds-wrapper.hbs"]({html:a(this).html()})),a(this).remove())})},e.prototype.getCore=function(){return this.core},e.prototype.editorSerialize=function(){var b=this._serializePreEmbeds();return a.each(b,function(c){var d=a("
").html(b[c].value);d.find(".medium-insert-embeds").removeAttr("contenteditable"),d.find(".medium-insert-embeds-overlay").remove(),b[c].value=d.html()}),b},e.prototype.add=function(){var a=this.$el.find(".medium-insert-active");a.html(this.templates["src/js/templates/core-empty-line.hbs"]().trim()),a.is("p")&&(a.replaceWith(''+a.html()+"
"),a=this.$el.find(".medium-insert-active"),this.getCore().moveCaret(a)),a.addClass("medium-insert-embeds medium-insert-embeds-input medium-insert-embeds-active"),this.togglePlaceholder({target:a.get(0)}),a.click(),this.getCore().hideButtons()},e.prototype.togglePlaceholder=function(c){var d,e,f,g=a(c.target),h=b.getSelection();h&&0!==h.rangeCount&&(d=h.getRangeAt(0),e=a(d.commonAncestorContainer),e.hasClass("medium-insert-embeds-active")?g=e:e.closest(".medium-insert-embeds-active").length&&(g=e.closest(".medium-insert-embeds-active")),g.hasClass("medium-insert-embeds-active")?(f=g.text().trim(),""===f&&g.hasClass("medium-insert-embeds-placeholder")===!1?g.addClass("medium-insert-embeds-placeholder").attr("data-placeholder",this.options.placeholder):""!==f&&g.hasClass("medium-insert-embeds-placeholder")&&g.removeClass("medium-insert-embeds-placeholder").removeAttr("data-placeholder")):this.$el.find(".medium-insert-embeds-active").remove())},e.prototype.fixRightClickOnPlaceholder=function(b){this.getCore().moveCaret(a(b.target))},e.prototype.processLink=function(a){var b,c=this.$el.find(".medium-insert-embeds-active");if(c.length)return b=c.text().trim(),""===b&&-1!==[8,46,13].indexOf(a.which)?void c.remove():void(13===a.which&&(a.preventDefault(),a.stopPropagation(),this.options.oembedProxy?this.oembed(b):this.parseUrl(b)))},e.prototype.oembed=function(c){var d=this;a.support.cors=!0,a.ajax({crossDomain:!0,cache:!1,url:this.options.oembedProxy,dataType:"json",data:{url:c},success:function(b){var c=b&&b.html;b&&!b.html&&"photo"===b.type&&b.url&&(c=' '),a.proxy(d,"embed",c)()},error:function(e,f,g){var h=function(){try{return JSON.parse(e.responseText)}catch(a){}}();"undefined"!=typeof b.console?b.console.log(h&&h.error||e.status||g.message):b.alert("Error requesting media from "+d.options.oembedProxy+" to insert: "+g+" (response status: "+e.status+")"),a.proxy(d,"convertBadEmbed",c)()}})},e.prototype.parseUrl=function(b){var c;return new RegExp(["youtube","youtu.be","vimeo","instagram"].join("|")).test(b)?(c=b.replace(/\n?/g,"").replace(/^((http(s)?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/(watch\?v=|v\/)?)([a-zA-Z0-9\-_]+)(.*)?$/,'
').replace(/^https?:\/\/vimeo\.com(\/.+)?\/([0-9]+)$/,'').replace(/^https?:\/\/instagram\.com\/p\/(.+)\/?$/,' '),void this.embed(/<("[^"]*"|'[^']*'|[^'">])*>/.test(c)?c:!1)):(a.proxy(this,"convertBadEmbed",b)(),!1)},e.prototype.embed=function(a){var b=this.$el.find(".medium-insert-embeds-active");return a?(b.after(this.templates["src/js/templates/embeds-wrapper.hbs"]({html:a})),b.remove(),this.$el.trigger("input"),-1!==a.indexOf("facebook")&&"undefined"!=typeof FB&&setTimeout(function(){FB.XFBML.parse()},2e3),void 0):(alert("Incorrect URL format specified"),!1)},e.prototype.convertBadEmbed=function(b){var c,d,e,f=this.templates["src/js/templates/core-empty-line.hbs"]().trim();c=this.$el.find(".medium-insert-embeds-active"),e=a(f),c.before(e),c.remove(),e.html(b),d=a(f),e.after(d),this.$el.trigger("input"),this.getCore().moveCaret(c)},e.prototype.selectEmbed=function(b){if(this.getCore().options.enabled){var c=a(b.target).hasClass("medium-insert-embeds")?a(b.target):a(b.target).closest(".medium-insert-embeds"),d=this;c.addClass("medium-insert-embeds-selected"),setTimeout(function(){d.addToolbar(),d.options.captions&&d.getCore().addCaption(c.find("figure"),d.options.captionPlaceholder)},50)}},e.prototype.unselectEmbed=function(b){var c=a(b.target).hasClass("medium-insert-embeds")?a(b.target):a(b.target).closest(".medium-insert-embeds"),d=this.$el.find(".medium-insert-embeds-selected");return c.hasClass("medium-insert-embeds-selected")?(d.not(c).removeClass("medium-insert-embeds-selected"),a(".medium-insert-embeds-toolbar, .medium-insert-embeds-toolbar2").remove(),this.getCore().removeCaptions(c.find("figcaption")),void((a(b.target).is(".medium-insert-caption-placeholder")||a(b.target).is("figcaption"))&&(c.removeClass("medium-insert-embeds-selected"),this.getCore().removeCaptionPlaceholder(c.find("figure"))))):(d.removeClass("medium-insert-embeds-selected"),a(".medium-insert-embeds-toolbar, .medium-insert-embeds-toolbar2").remove(),void(a(b.target).is(".medium-insert-caption-placeholder")?this.getCore().removeCaptionPlaceholder(c.find("figure")):a(b.target).is("figcaption")===!1&&this.getCore().removeCaptions()))},e.prototype.removeEmbed=function(b){var c,d;(8===b.which||46===b.which)&&(c=this.$el.find(".medium-insert-embeds-selected"),c.length&&(b.preventDefault(),a(".medium-insert-embeds-toolbar, .medium-insert-embeds-toolbar2").remove(),d=a(this.templates["src/js/templates/core-empty-line.hbs"]().trim()),c.before(d),c.remove(),this.getCore().hideAddons(),this.getCore().moveCaret(d),this.$el.trigger("input")))},e.prototype.addToolbar=function(){var b,c,d,e=this.$el.find(".medium-insert-embeds-selected"),f=!1;0!==e.length&&(a("body").append(this.templates["src/js/templates/embeds-toolbar.hbs"]({styles:this.options.styles,actions:this.options.actions}).trim()),b=a(".medium-insert-embeds-toolbar"),c=a(".medium-insert-embeds-toolbar2"),d=e.offset().top-b.height()-8-2-5,0>d&&(d=0),b.css({top:d,left:e.offset().left+e.width()/2-b.width()/2}).show(),c.css({top:e.offset().top+2,left:e.offset().left+e.width()-c.width()-4}).show(),b.find("button").each(function(){e.hasClass("medium-insert-embeds-"+a(this).data("action"))&&(a(this).addClass("medium-editor-button-active"),f=!0)}),f===!1&&b.find("button").first().addClass("medium-editor-button-active"))},e.prototype.toolbarAction=function(b){var c=a(b.target).is("button")?a(b.target):a(b.target).closest("button"),d=c.closest("li"),e=d.closest("ul"),f=e.find("li"),g=this.$el.find(".medium-insert-embeds-selected"),h=this;c.addClass("medium-editor-button-active"),d.siblings().find(".medium-editor-button-active").removeClass("medium-editor-button-active"),f.find("button").each(function(){var b="medium-insert-embeds-"+a(this).data("action");a(this).hasClass("medium-editor-button-active")?(g.addClass(b),h.options.styles[a(this).data("action")].added&&h.options.styles[a(this).data("action")].added(g)):(g.removeClass(b),h.options.styles[a(this).data("action")].removed&&h.options.styles[a(this).data("action")].removed(g))}),this.$el.trigger("input")},e.prototype.toolbar2Action=function(b){var c=a(b.target).is("button")?a(b.target):a(b.target).closest("button"),d=this.options.actions[c.data("action")].clicked;d&&d(this.$el.find(".medium-insert-embeds-selected")),this.$el.trigger("input")},a.fn[f+g]=function(b){return this.each(function(){a.data(this,"plugin_"+f+g)||a.data(this,"plugin_"+f+g,new e(this,b))})}}(jQuery,window,document),function(a,b,c,d){"use strict";function e(c,d){this.el=c,this.$el=a(c),this.templates=b.MediumInsert.Templates,this.core=this.$el.data("plugin_"+f),this.options=a.extend(!0,{},h,d),this._defaults=h,this._name=f,this.options.preview&&!b.FileReader&&(this.options.preview=!1),this.core.getEditor()&&(this.core.getEditor()._serializePreImages=this.core.getEditor().serialize,this.core.getEditor().serialize=this.editorSerialize),this.init()}var f="mediumInsert",g="Images",h={label:' ',uploadScript:null,deleteScript:"delete.php",preview:!0,captions:!0,captionPlaceholder:"Type caption for image (optional)",autoGrid:3,formData:null,fileUploadOptions:{url:"upload.php",acceptFileTypes:/(\.|\/)(gif|jpe?g|png)$/i},styles:{wide:{label:' '},left:{label:' '},right:{label:' '},grid:{label:' '}},actions:{remove:{label:' ',clicked:function(){var b=a.Event("keydown");b.which=8,a(c).trigger(b)}}},sorting:function(){var b=this;a(".medium-insert-images").sortable({group:"medium-insert-images",containerSelector:".medium-insert-images",itemSelector:"figure",placeholder:'',handle:"img",nested:!1,vertical:!1,afterMove:function(){b.$el.trigger("input")}})}};e.prototype.init=function(){var a=this.$el.find(".medium-insert-images");a.find("figcaption").attr("contenteditable",!0),a.find("figure").attr("contenteditable",!1),this.events(),this.backwardsCompatibility(),this.sorting()},e.prototype.events=function(){a(c).on("click",a.proxy(this,"unselectImage")).on("keydown",a.proxy(this,"removeImage")).on("click",".medium-insert-images-toolbar .medium-editor-action",a.proxy(this,"toolbarAction")).on("click",".medium-insert-images-toolbar2 .medium-editor-action",a.proxy(this,"toolbar2Action")),this.$el.on("click",".medium-insert-images img",a.proxy(this,"selectImage"))},e.prototype.backwardsCompatibility=function(){this.$el.find(".mediumInsert").removeClass("mediumInsert").addClass("medium-insert-images"),this.$el.find(".medium-insert-images.small").removeClass("small").addClass("medium-insert-images-left")},e.prototype.getCore=function(){return this.core},e.prototype.editorSerialize=function(){var b=this._serializePreImages();return a.each(b,function(c){var d=a("
").html(b[c].value);d.find(".medium-insert-images").find("figcaption, figure").removeAttr("contenteditable"),b[c].value=d.html()}),b},e.prototype.add=function(){var b=this,c=a(this.templates["src/js/templates/images-fileupload.hbs"]()),d={dataType:"json",add:function(c,d){a.proxy(b,"uploadAdd",c,d)()},done:function(c,d){a.proxy(b,"uploadDone",c,d)()}};this.options.uploadScript&&(d.url=this.options.uploadScript,this.getCore().deprecated("uploadScript","fileUploadOptions","2.0")),this.options.formData&&(d.formData=this.options.formData,this.getCore().deprecated("formData","fileUploadOptions","2.0")),(new XMLHttpRequest).upload&&(d.progress=function(c,d){a.proxy(b,"uploadProgress",c,d)()},d.progressall=function(c,d){a.proxy(b,"uploadProgressall",c,d)()}),c.fileupload(a.extend(!0,{},this.options.fileUploadOptions,d)),c.click()},e.prototype.uploadAdd=function(b,c){var d,e=this.$el.find(".medium-insert-active"),f=this;this.getCore().hideButtons(),e.is("p")&&(e.replaceWith(''+e.html()+"
"),e=this.$el.find(".medium-insert-active"),this.getCore().moveCaret(e)),e.addClass("medium-insert-images"),this.options.preview===!1&&0===e.find("progress").length&&(new XMLHttpRequest).upload&&e.append(this.templates["src/js/templates/images-progressbar.hbs"]()),(c.autoUpload||c.autoUpload!==!1&&a(b.target).fileupload("option","autoUpload"))&&c.process().done(function(){f.options.preview?(d=new FileReader,d.onload=function(b){a.proxy(f,"showImage",b.target.result,c)()},d.readAsDataURL(c.files[0])):c.submit()})},e.prototype.uploadProgressall=function(a,b){var c,d;this.options.preview===!1&&(c=parseInt(b.loaded/b.total*100,10),d=this.$el.find(".medium-insert-active").find("progress"),d.attr("value",c).text(c),100===c&&d.remove())},e.prototype.uploadProgress=function(a,b){var c,d;this.options.preview&&(c=100-parseInt(b.loaded/b.total*100,10),d=b.context.find(".medium-insert-images-progress"),d.css("width",c+"%"),0===c&&d.remove())},e.prototype.uploadDone=function(b,c){var d=a.proxy(this,"showImage",c.result.files[0].url,c)();this.getCore().clean(),this.sorting(),this.options.uploadCompleted&&this.options.uploadCompleted(d,c)},e.prototype.showImage=function(b,c){var d,e,f=this.$el.find(".medium-insert-active");return f.click(),e=this,this.options.preview&&c.context?(d=this.getDOMImage(),d.onload=function(){c.context.find("img").attr("src",d.src),e.$el.trigger("input")},d.src=b):(c.context=a(this.templates["src/js/templates/images-image.hbs"]({img:b,progress:this.options.preview})).appendTo(f),f.find("br").remove(),this.options.autoGrid&&f.find("figure").length>=this.options.autoGrid&&(a.each(this.options.styles,function(a,b){var c="medium-insert-images-"+a;f.removeClass(c),b.removed&&b.removed(f)}),f.addClass("medium-insert-images-grid"),this.options.styles.grid.added&&this.options.styles.grid.added(f)),this.options.preview&&c.submit()),this.$el.trigger("input"),c.context},e.prototype.getDOMImage=function(){return new b.Image},e.prototype.selectImage=function(b){if(this.getCore().options.enabled){var c=a(b.target),d=this;this.$el.blur(),c.addClass("medium-insert-image-active"),c.closest(".medium-insert-images").addClass("medium-insert-active"),setTimeout(function(){d.addToolbar(),d.options.captions&&d.getCore().addCaption(c.closest("figure"),d.options.captionPlaceholder)},50)}},e.prototype.unselectImage=function(b){var c=a(b.target),d=this.$el.find(".medium-insert-image-active");return c.is("img")&&c.hasClass("medium-insert-image-active")?(d.not(c).removeClass("medium-insert-image-active"),a(".medium-insert-images-toolbar, .medium-insert-images-toolbar2").remove(),void this.getCore().removeCaptions(c)):(d.removeClass("medium-insert-image-active"),a(".medium-insert-images-toolbar, .medium-insert-images-toolbar2").remove(),void(c.is(".medium-insert-caption-placeholder")?this.getCore().removeCaptionPlaceholder(d.closest("figure")):c.is("figcaption")===!1&&this.getCore().removeCaptions()))},e.prototype.removeImage=function(b){var c,d,e;(8===b.which||46===b.which)&&(c=this.$el.find(".medium-insert-image-active"),c.length&&(b.preventDefault(),this.deleteFile(c.attr("src")),d=c.closest(".medium-insert-images"),c.closest("figure").remove(),a(".medium-insert-images-toolbar, .medium-insert-images-toolbar2").remove(),0===d.find("figure").length&&(e=d.next(),(e.is("p")===!1||""!==e.text())&&(e=a(this.templates["src/js/templates/core-empty-line.hbs"]().trim()),d.before(e)),d.remove(),this.getCore().hideAddons(),this.getCore().moveCaret(e)),this.$el.trigger("input")))},e.prototype.deleteFile=function(b){this.options.deleteScript&&a.post(this.options.deleteScript,{file:b})},e.prototype.addToolbar=function(){var b,c,d,e=this.$el.find(".medium-insert-image-active"),f=e.closest(".medium-insert-images"),g=!1;a("body").append(this.templates["src/js/templates/images-toolbar.hbs"]({styles:this.options.styles,actions:this.options.actions
+}).trim()),b=a(".medium-insert-images-toolbar"),c=a(".medium-insert-images-toolbar2"),d=e.offset().top-b.height()-8-2-5,0>d&&(d=0),b.css({top:d,left:e.offset().left+e.width()/2-b.width()/2}).show(),c.css({top:e.offset().top+2,left:e.offset().left+e.width()-c.width()-4}).show(),b.find("button").each(function(){f.hasClass("medium-insert-images-"+a(this).data("action"))&&(a(this).addClass("medium-editor-button-active"),g=!0)}),g===!1&&b.find("button").first().addClass("medium-editor-button-active")},e.prototype.toolbarAction=function(b){var c=a(b.target).is("button")?a(b.target):a(b.target).closest("button"),d=c.closest("li"),e=d.closest("ul"),f=e.find("li"),g=this.$el.find(".medium-insert-active"),h=this;c.addClass("medium-editor-button-active"),d.siblings().find(".medium-editor-button-active").removeClass("medium-editor-button-active"),f.find("button").each(function(){var b="medium-insert-images-"+a(this).data("action");a(this).hasClass("medium-editor-button-active")?(g.addClass(b),h.options.styles[a(this).data("action")].added&&h.options.styles[a(this).data("action")].added(g)):(g.removeClass(b),h.options.styles[a(this).data("action")].removed&&h.options.styles[a(this).data("action")].removed(g))}),this.getCore().hideButtons(),this.$el.trigger("input")},e.prototype.toolbar2Action=function(b){var c=a(b.target).is("button")?a(b.target):a(b.target).closest("button"),d=this.options.actions[c.data("action")].clicked;d&&d(this.$el.find(".medium-insert-image-active")),this.getCore().hideButtons(),this.$el.trigger("input")},e.prototype.sorting=function(){this.options.sorting()},a.fn[f+g]=function(b){return this.each(function(){a.data(this,"plugin_"+f+g)||a.data(this,"plugin_"+f+g,new e(this,b))})}}(jQuery,window,document);
\ No newline at end of file
diff --git a/public/editor/medium-editor/js/medium-editor.min.js b/public/editor/medium-editor/js/medium-editor.min.js
new file mode 100644
index 0000000..0635067
--- /dev/null
+++ b/public/editor/medium-editor/js/medium-editor.min.js
@@ -0,0 +1,3 @@
+"classList"in document.createElement("_")||!function(a){"use strict";if("Element"in a){var b="classList",c="prototype",d=a.Element[c],e=Object,f=String[c].trim||function(){return this.replace(/^\s+|\s+$/g,"")},g=Array[c].indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(b in this&&this[b]===a)return b;return-1},h=function(a,b){this.name=a,this.code=DOMException[a],this.message=b},i=function(a,b){if(""===b)throw new h("SYNTAX_ERR","An invalid or illegal string was specified");if(/\s/.test(b))throw new h("INVALID_CHARACTER_ERR","String contains an invalid character");return g.call(a,b)},j=function(a){for(var b=f.call(a.getAttribute("class")||""),c=b?b.split(/\s+/):[],d=0,e=c.length;e>d;d++)this.push(c[d]);this._updateClassName=function(){a.setAttribute("class",this.toString())}},k=j[c]=[],l=function(){return new j(this)};if(h[c]=Error[c],k.item=function(a){return this[a]||null},k.contains=function(a){return a+="",-1!==i(this,a)},k.add=function(){var a,b=arguments,c=0,d=b.length,e=!1;do a=b[c]+"",-1===i(this,a)&&(this.push(a),e=!0);while(++ci;i++)e+=String.fromCharCode(f[i]);c.push(e)}else if("Blob"===b(a)||"File"===b(a)){if(!g)throw new h("NOT_READABLE_ERR");var k=new g;c.push(k.readAsBinaryString(a))}else a instanceof d?"base64"===a.encoding&&p?c.push(p(a.data)):"URI"===a.encoding?c.push(decodeURIComponent(a.data)):"raw"===a.encoding&&c.push(a.data):("string"!=typeof a&&(a+=""),c.push(unescape(encodeURIComponent(a))))},e.getBlob=function(a){return arguments.length||(a=null),new d(this.data.join(""),a,"raw")},e.toString=function(){return"[object BlobBuilder]"},f.slice=function(a,b,c){var e=arguments.length;return 3>e&&(c=null),new d(this.data.slice(a,e>1?b:this.data.length),c,this.encoding)},f.toString=function(){return"[object Blob]"},f.close=function(){this.size=0,delete this.data},c}(a);a.Blob=function(a,b){var d=b?b.type||"":"",e=new c;if(a)for(var f=0,g=a.length;g>f;f++)e.append(Uint8Array&&a[f]instanceof Uint8Array?a[f].buffer:a[f]);var h=e.getBlob(d);return!h.slice&&h.webkitSlice&&(h.slice=h.webkitSlice),h};var d=Object.getPrototypeOf||function(a){return a.__proto__};a.Blob.prototype=d(new a.Blob)}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this.content||this),function(a,b){"use strict";"object"==typeof module?module.exports=b:"function"==typeof define&&define.amd?define(function(){return b}):a.MediumEditor=b}(this,function(){"use strict";function a(a,b){return this.init(a,b)}var b;!function(a){function c(b,c,d){d||(d=a);try{for(var e=0;e=0,keyCode:{BACKSPACE:8,TAB:9,ENTER:13,ESCAPE:27,SPACE:32,DELETE:46},isMetaCtrlKey:function(a){return this.isMac&&a.metaKey||!this.isMac&&a.ctrlKey?!0:!1},parentElements:["p","h1","h2","h3","h4","h5","h6","blockquote","pre"],extend:function(){var a=[!0].concat(Array.prototype.slice.call(arguments));return d.apply(this,a)},defaults:function(){var a=[!1].concat(Array.prototype.slice.call(arguments));return d.apply(this,a)},derives:function(a,b){function c(){}var e=b.prototype;return c.prototype=a.prototype,b.prototype=new c,b.prototype.constructor=a,b.prototype=d(!1,b.prototype,e),b},findAdjacentTextNodeWithContent:function(a,b,c){var d,e=!1,f=c.createNodeIterator(a,NodeFilter.SHOW_TEXT,null,!1);for(d=f.nextNode();d;){if(d===b)e=!0;else if(e&&3===d.nodeType&&d.nodeValue&&d.nodeValue.trim().length>0)break;d=f.nextNode()}return d},isDescendant:function(a,b,c){if(!a||!b)return!1;if(c&&a===b)return!0;for(var d=b.parentNode;null!==d;){if(d===a)return!0;d=d.parentNode}return!1},isElement:function(a){return!(!a||1!==a.nodeType)},now:Date.now,throttle:function(a,b){var c,d,e,f=50,g=null,h=0,i=function(){h=Date.now(),g=null,e=a.apply(c,d),g||(c=d=null)};return b||0===b||(b=f),function(){var f=Date.now(),j=b-(f-h);return c=this,d=arguments,0>=j||j>b?(g&&(clearTimeout(g),g=null),h=f,e=a.apply(c,d),g||(c=d=null)):g||(g=setTimeout(i,j)),e}},traverseUp:function(a,b){if(!a)return!1;do{if(1===a.nodeType){if(b(a))return a;if(a.getAttribute("data-medium-element"))return!1}a=a.parentNode}while(a);return!1},htmlEntities:function(a){return String(a).replace(/&/g,"&").replace(//g,">").replace(/"/g,""")},insertHTMLCommand:function(a,b){var c,d,e,f,g,h,i;if(a.queryCommandSupported("insertHTML"))try{return a.execCommand("insertHTML",!1,b)}catch(j){}if(c=a.defaultView.getSelection(),c.getRangeAt&&c.rangeCount){if(d=c.getRangeAt(0),i=d.commonAncestorContainer,3===i.nodeType&&i.nodeValue===d.toString()||3!==i.nodeType&&i.innerHTML===d.toString()){for(;i.parentNode&&1===i.parentNode.childNodes.length&&!i.parentNode.getAttribute("data-medium-element");)i=i.parentNode;d.selectNode(i)}for(d.deleteContents(),e=a.createElement("div"),e.innerHTML=b,f=a.createDocumentFragment();e.firstChild;)g=e.firstChild,h=f.appendChild(g);d.insertNode(f),h&&(d=d.cloneRange(),d.setStartAfter(h),d.collapse(!0),c.removeAllRanges(),c.addRange(d))}},getSelectionRange:function(a){var b=a.getSelection();return 0===b.rangeCount?null:b.getRangeAt(0)},getSelectionStart:function(a){var b=a.getSelection().anchorNode,c=b&&3===b.nodeType?b.parentNode:b;return c},getSelectionData:function(a){var b;for(a&&a.tagName&&(b=a.tagName.toLowerCase());a&&-1===this.parentElements.indexOf(b);)a=a.parentNode,a&&a.tagName&&(b=a.tagName.toLowerCase());return{el:a,tagName:b}},execFormatBlock:function(a,b){var c=this.getSelectionData(this.getSelectionStart(a));if("blockquote"===b&&c.el&&"blockquote"===c.el.parentNode.tagName.toLowerCase())return a.execCommand("outdent",!1,null);if(c.tagName===b&&(b="p"),this.isIE){if("blockquote"===b)return a.execCommand("indent",!1,b);b="<"+b+">"}return a.execCommand("formatBlock",!1,b)},setTargetBlank:function(a){var b;if("a"===a.tagName.toLowerCase())a.target="_blank";else for(a=a.getElementsByTagName("a"),b=0;bB",contentFA:' ',key:"b"},italic:{name:"italic",action:"italic",aria:"italic",tagNames:["i","em"],style:{prop:"font-style",value:"italic"},useQueryState:!0,contentDefault:"I ",contentFA:' ',key:"i"},underline:{name:"underline",action:"underline",aria:"underline",tagNames:["u"],style:{prop:"text-decoration",value:"underline"},useQueryState:!0,contentDefault:"U ",contentFA:' ',key:"u"},strikethrough:{name:"strikethrough",action:"strikethrough",aria:"strike through",tagNames:["strike"],style:{prop:"text-decoration",value:"line-through"},useQueryState:!0,contentDefault:"A ",contentFA:' '},superscript:{name:"superscript",action:"superscript",aria:"superscript",tagNames:["sup"],contentDefault:"x1 ",contentFA:' '},subscript:{name:"subscript",action:"subscript",aria:"subscript",tagNames:["sub"],contentDefault:"x1 ",contentFA:' '},image:{name:"image",action:"image",aria:"image",tagNames:["img"],contentDefault:"image ",contentFA:' '},quote:{name:"quote",action:"append-blockquote",aria:"blockquote",tagNames:["blockquote"],contentDefault:"“ ",contentFA:' '},orderedlist:{name:"orderedlist",action:"insertorderedlist",aria:"ordered list",tagNames:["ol"],useQueryState:!0,contentDefault:"1. ",contentFA:' '},unorderedlist:{name:"unorderedlist",action:"insertunorderedlist",aria:"unordered list",tagNames:["ul"],useQueryState:!0,contentDefault:"• ",contentFA:' '},pre:{name:"pre",action:"append-pre",aria:"preformatted text",tagNames:["pre"],contentDefault:"0101 ",contentFA:' '},indent:{name:"indent",action:"indent",aria:"indent",tagNames:[],contentDefault:"→ ",contentFA:' '},outdent:{name:"outdent",action:"outdent",aria:"outdent",tagNames:[],contentDefault:"← ",contentFA:' '},justifyCenter:{name:"justifyCenter",action:"justifyCenter",aria:"center justify",tagNames:[],style:{prop:"text-align",value:"center"},contentDefault:"C ",contentFA:' '},justifyFull:{name:"justifyFull",action:"justifyFull",aria:"full justify",tagNames:[],style:{prop:"text-align",value:"justify"},contentDefault:"J ",contentFA:' '},justifyLeft:{name:"justifyLeft",action:"justifyLeft",aria:"left justify",tagNames:[],style:{prop:"text-align",value:"left"},contentDefault:"L ",contentFA:' '},justifyRight:{name:"justifyRight",action:"justifyRight",aria:"right justify",tagNames:[],style:{prop:"text-align",value:"right"},contentDefault:"R ",contentFA:' '},header1:{name:"header1",action:function(a){return"append-"+a.firstHeader},aria:function(a){return a.firstHeader},tagNames:function(a){return[a.firstHeader]},contentDefault:"H1 "},header2:{name:"header2",action:function(a){return"append-"+a.secondHeader},aria:function(a){return a.secondHeader},tagNames:function(a){return[a.secondHeader]},contentDefault:"H2 "},removeFormat:{name:"removeFormat",aria:"remove formatting",action:"removeFormat",contentDefault:"X ",contentFA:' '}}}();var d;!function(){d={allowMultiParagraphSelection:!0,anchorInputPlaceholder:"Paste or type a link",anchorInputCheckboxLabel:"Open in new window",anchorPreviewHideDelay:500,buttons:["bold","italic","underline","anchor","header1","header2","quote"],buttonLabels:!1,checkLinkFormat:!1,delay:0,diffLeft:0,diffTop:-10,disableReturn:!1,disableDoubleReturn:!1,disableToolbar:!1,disableAnchorPreview:!1,disableEditing:!1,disablePlaceholders:!1,toolbarAlign:"center",elementsContainer:!1,imageDragging:!0,standardizeSelectionStart:!1,contentWindow:window,ownerDocument:document,firstHeader:"h3",placeholder:"Type your text",secondHeader:"h4",targetBlank:!1,anchorTarget:!1,anchorButton:!1,anchorButtonClass:"btn",extensions:{},activeButtonClass:"medium-editor-button-active",firstButtonClass:"medium-editor-button-first",lastButtonClass:"medium-editor-button-last",spellcheck:!0,paste:{forcePlainText:!0,cleanPastedHTML:!1,cleanAttrs:["class","style","dir"],cleanTags:["meta"]}}}();var e;!function(){e=function(a){b.extend(this,a)},e.extend=function(a){var c,d=this;c=a&&a.hasOwnProperty("constructor")?a.constructor:function(){return d.apply(this,arguments)},b.extend(c,d);var e=function(){this.constructor=c};return e.prototype=d.prototype,c.prototype=new e,a&&b.extend(c.prototype,a),c},e.prototype={init:function(){},parent:!1,base:null,name:null,checkState:null,getButton:null,queryCommandState:null,isActive:null,isAlreadyApplied:null,setActive:null,setInactive:null,onHide:null}}();var f;!function(){f={findMatchingSelectionParent:function(a,c){var d,e,f=c.getSelection();return 0===f.rangeCount?!1:(d=f.getRangeAt(0),e=d.commonAncestorContainer,b.traverseUp(e,a))},getSelectionElement:function(a){return this.findMatchingSelectionParent(function(a){return a.getAttribute("data-medium-element")},a)},selectionInContentEditableFalse:function(a){return this.findMatchingSelectionParent(function(a){return a&&"#text"!==a.nodeName&&"false"===a.getAttribute("contenteditable")},a)},getSelectionHtml:function(){var a,b,c,d="",e=this.options.contentWindow.getSelection();if(e.rangeCount){for(c=this.options.ownerDocument.createElement("div"),a=0,b=e.rangeCount;b>a;a+=1)c.appendChild(e.getRangeAt(a).cloneContents());d=c.innerHTML}return d},getCaretOffsets:function(a,b){var c,d;return b||(b=window.getSelection().getRangeAt(0)),c=b.cloneRange(),d=b.cloneRange(),c.selectNodeContents(a),c.setEnd(b.endContainer,b.endOffset),d.selectNodeContents(a),d.setStart(b.endContainer,b.endOffset),{left:c.toString().length,right:d.toString().length}},rangeSelectsSingleNode:function(a){var b=a.startContainer;return b===a.endContainer&&b.hasChildNodes()&&a.endOffset===a.startOffset+1},getSelectedParentElement:function(a){var b=null;return b=this.rangeSelectsSingleNode(a)&&3!==a.startContainer.childNodes[a.startOffset].nodeType?a.startContainer.childNodes[a.startOffset]:3===a.startContainer.nodeType?a.startContainer.parentNode:a.startContainer},getSelectedElements:function(a){var b,c,d,e=a.getSelection();if(!e.rangeCount||!e.getRangeAt(0).commonAncestorContainer)return[];if(b=e.getRangeAt(0),3===b.commonAncestorContainer.nodeType){for(c=[],d=b.commonAncestorContainer;d.parentNode&&1===d.parentNode.childNodes.length;)c.push(d.parentNode),d=d.parentNode;return c}return[].filter.call(b.commonAncestorContainer.getElementsByTagName("*"),function(a){return"function"==typeof e.containsNode?e.containsNode(a,!0):!0})},selectNode:function(a,b){var c=b.createRange(),d=b.getSelection();c.selectNodeContents(a),d.removeAllRanges(),d.addRange(c)}}}();var g;!function(){g=function(a){this.base=a,this.options=this.base.options,this.events=[],this.customEvents={},this.listeners={}},g.prototype={attachDOMEvent:function(a,b,c,d){a.addEventListener(b,c,d),this.events.push([a,b,c,d])},detachDOMEvent:function(a,b,c,d){var e,f=this.indexOfListener(a,b,c,d);-1!==f&&(e=this.events.splice(f,1)[0],e[0].removeEventListener(e[1],e[2],e[3]))},indexOfListener:function(a,b,c,d){var e,f,g;for(e=0,f=this.events.length;f>e;e+=1)if(g=this.events[e],g[0]===a&&g[1]===b&&g[2]===c&&g[3]===d)return e;return-1},detachAllDOMEvents:function(){for(var a=this.events.pop();a;)a[0].removeEventListener(a[1],a[2],a[3]),a=this.events.pop()},attachCustomEvent:function(a,b){this.setupListener(a),this.listeners[a]&&(this.customEvents[a]||(this.customEvents[a]=[]),this.customEvents[a].push(b))},detachCustomEvent:function(a,b){var c=this.indexOfCustomListener(a,b);-1!==c&&this.customEvents[a].splice(c,1)},indexOfCustomListener:function(a,b){return this.customEvents[a]&&this.customEvents[a].length?this.customEvents[a].indexOf(b):-1},detachAllCustomEvents:function(){this.customEvents={}},triggerCustomEvent:function(a,b,c){this.customEvents[a]&&this.customEvents[a].forEach(function(a){a(b,c)})},setupListener:function(a){if(!this.listeners[a])switch(a){case"externalInteraction":this.attachDOMEvent(this.options.ownerDocument.body,"mousedown",this.handleBodyMousedown.bind(this),!0),this.attachDOMEvent(this.options.ownerDocument.body,"click",this.handleBodyClick.bind(this),!0),this.attachDOMEvent(this.options.ownerDocument.body,"focus",this.handleBodyFocus.bind(this),!0),this.listeners[a]=!0;break;case"blur":this.setupListener("externalInteraction"),this.listeners[a]=!0;break;case"focus":this.setupListener("externalInteraction"),this.listeners[a]=!0;break;case"editableClick":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"click",this.handleClick.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableBlur":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"blur",this.handleBlur.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeypress":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"keypress",this.handleKeypress.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeyup":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"keyup",this.handleKeyup.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeydown":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"keydown",this.handleKeydown.bind(this))}.bind(this)),this.listeners[a]=!0;break;case"editableKeydownEnter":this.setupListener("editableKeydown"),this.listeners[a]=!0;break;case"editableKeydownTab":this.setupListener("editableKeydown"),this.listeners[a]=!0;break;case"editableKeydownDelete":this.setupListener("editableKeydown"),this.listeners[a]=!0;break;case"editableMouseover":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"mouseover",this.handleMouseover.bind(this))},this),this.listeners[a]=!0;break;case"editableDrag":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"dragover",this.handleDragging.bind(this)),this.attachDOMEvent(a,"dragleave",this.handleDragging.bind(this))},this),this.listeners[a]=!0;break;case"editableDrop":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"drop",this.handleDrop.bind(this))},this),this.listeners[a]=!0;break;case"editablePaste":this.base.elements.forEach(function(a){this.attachDOMEvent(a,"paste",this.handlePaste.bind(this))},this),this.listeners[a]=!0}},focusElement:function(a){a.focus(),this.updateFocus(a,{target:a,type:"focus"})},updateFocus:function(a,c){var d,e,f=this.base.toolbar?this.base.toolbar.getToolbarElement():null,g=this.base.getExtensionByName("anchor-preview"),h=g&&g.getPreviewElement?g.getPreviewElement():null;this.base.elements.some(function(a){return!d&&a.getAttribute("data-medium-focused")&&(d=a),!!d},this),d&&"click"===c.type&&this.lastMousedownTarget&&(b.isDescendant(d,this.lastMousedownTarget,!0)||b.isDescendant(f,this.lastMousedownTarget,!0)||b.isDescendant(h,this.lastMousedownTarget,!0))&&(e=d),e||this.base.elements.some(function(c){return!e&&b.isDescendant(c,a,!0)&&(e=c),!!e},this);var i=!b.isDescendant(d,a,!0)&&!b.isDescendant(f,a,!0)&&!b.isDescendant(h,a,!0);e!==d&&(d&&i&&(d.removeAttribute("data-medium-focused"),this.triggerCustomEvent("blur",c,d)),e&&(e.setAttribute("data-medium-focused",!0),this.triggerCustomEvent("focus",c,e))),i&&this.triggerCustomEvent("externalInteraction",c)},handleBodyClick:function(a){this.updateFocus(a.target,a)},handleBodyFocus:function(a){this.updateFocus(a.target,a)},handleBodyMousedown:function(a){this.lastMousedownTarget=a.target},handleClick:function(a){this.triggerCustomEvent("editableClick",a,a.currentTarget)},handleBlur:function(a){this.triggerCustomEvent("editableBlur",a,a.currentTarget)},handleKeypress:function(a){this.triggerCustomEvent("editableKeypress",a,a.currentTarget)},handleKeyup:function(a){this.triggerCustomEvent("editableKeyup",a,a.currentTarget)},handleMouseover:function(a){this.triggerCustomEvent("editableMouseover",a,a.currentTarget)},handleDragging:function(a){this.triggerCustomEvent("editableDrag",a,a.currentTarget)},handleDrop:function(a){this.triggerCustomEvent("editableDrop",a,a.currentTarget)},handlePaste:function(a){this.triggerCustomEvent("editablePaste",a,a.currentTarget)},handleKeydown:function(a){switch(this.triggerCustomEvent("editableKeydown",a,a.currentTarget),a.which){case b.keyCode.ENTER:this.triggerCustomEvent("editableKeydownEnter",a,a.currentTarget);break;case b.keyCode.TAB:this.triggerCustomEvent("editableKeydownTab",a,a.currentTarget);break;case b.keyCode.DELETE:case b.keyCode.BACKSPACE:this.triggerCustomEvent("editableKeydownDelete",a,a.currentTarget)}}}}();var h;!function(){h=function(a,b){this.options=a,this.name=a.name,this.init(b)},h.prototype={init:function(a){this.base=a,this.button=this.createButton(),this.base.on(this.button,"click",this.handleClick.bind(this)),this.options.key&&this.base.subscribe("editableKeydown",this.handleKeydown.bind(this))},getButton:function(){return this.button},getAction:function(){return"function"==typeof this.options.action?this.options.action(this.base.options):this.options.action},getAria:function(){return"function"==typeof this.options.aria?this.options.aria(this.base.options):this.options.aria},getTagNames:function(){return"function"==typeof this.options.tagNames?this.options.tagNames(this.base.options):this.options.tagNames},createButton:function(){var a=this.base.options.ownerDocument.createElement("button"),b=this.options.contentDefault,c=this.getAria();return a.classList.add("medium-editor-action"),a.classList.add("medium-editor-action-"+this.name),a.setAttribute("data-action",this.getAction()),c&&(a.setAttribute("title",c),a.setAttribute("aria-label",c)),this.base.options.buttonLabels&&("fontawesome"===this.base.options.buttonLabels&&this.options.contentFA?b=this.options.contentFA:"object"==typeof this.base.options.buttonLabels&&this.base.options.buttonLabels[this.name]&&(b=this.base.options.buttonLabels[this.options.name])),a.innerHTML=b,a},handleKeydown:function(a){var c,d=String.fromCharCode(a.which||a.keyCode).toLowerCase();this.options.key===d&&b.isMetaCtrlKey(a)&&(a.preventDefault(),a.stopPropagation(),c=this.getAction(),c&&this.base.execAction(c))},handleClick:function(a){a.preventDefault(),a.stopPropagation();var b=this.getAction();b&&this.base.execAction(b)},isActive:function(){return this.button.classList.contains(this.base.options.activeButtonClass)},setInactive:function(){this.button.classList.remove(this.base.options.activeButtonClass),delete this.knownState},setActive:function(){this.button.classList.add(this.base.options.activeButtonClass),delete this.knownState},queryCommandState:function(){var a=null;return this.options.useQueryState&&(a=this.base.queryCommandState(this.getAction())),a},isAlreadyApplied:function(a){var b,c,d=!1,e=this.getTagNames();return this.knownState===!1||this.knownState===!0?this.knownState:(e&&e.length>0&&a.tagName&&(d=-1!==e.indexOf(a.tagName.toLowerCase())),!d&&this.options.style&&(b=this.options.style.value.split("|"),c=this.base.options.contentWindow.getComputedStyle(a,null).getPropertyValue(this.options.style.prop),b.forEach(function(a){this.knownState||(d=-1!==c.indexOf(a),(d||"text-decoration"!==this.options.style.prop)&&(this.knownState=d))},this)),d)}}}();var i;!function(){function a(){return[[new RegExp(/<[^>]*docs-internal-guid[^>]*>/gi),""],[new RegExp(/<\/b>( ]*>)?$/gi),""],[new RegExp(/\s+<\/span>/g)," "],[new RegExp(/ /g)," "],[new RegExp(/]*(font-style:italic;font-weight:bold|font-weight:bold;font-style:italic)[^>]*>/gi),''],[new RegExp(/]*font-style:italic[^>]*>/gi),''],[new RegExp(/]*font-weight:bold[^>]*>/gi),''],[new RegExp(/<(\/?)(i|b|a)>/gi),"<$1$2>"],[new RegExp(/<a(?:(?!href).)+href=(?:"|”|“|"|“|”)(((?!"|”|“|"|“|”).)*)(?:"|”|“|"|“|”)(?:(?!>).)*>/gi),''],[new RegExp(/<\/p>\n+/gi),""],[new RegExp(/\n+/gi),""]]}i=e.extend({forcePlainText:!0,cleanPastedHTML:!1,cleanReplacements:[],cleanAttrs:["class","style","dir"],cleanTags:["meta"],window:window,document:document,targetBlank:!1,disableReturn:!1,parent:!0,init:function(){(this.forcePlainText||this.cleanPastedHTML)&&this.base.subscribe("editablePaste",this.handlePaste.bind(this))},handlePaste:function(a,c){var d,e,f,g,h="",i="text/html",j="text/plain";if(this.window.clipboardData&&void 0===a.clipboardData&&(a.clipboardData=this.window.clipboardData,i="Text",j="Text"),a.clipboardData&&a.clipboardData.getData&&!a.defaultPrevented){if(a.preventDefault(),f=a.clipboardData.getData(i),g=a.clipboardData.getData(j),f||(f=g),this.cleanPastedHTML&&f)return this.cleanPaste(f);if(this.disableReturn||c.getAttribute("data-disable-return"))h=b.htmlEntities(g);else if(d=g.split(/[\r\n]+/g),d.length>1)for(e=0;e"+b.htmlEntities(d[e])+"
");else h=b.htmlEntities(d[0]);b.insertHTMLCommand(this.document,h)}},cleanPaste:function(c){var d,e,g,h=f.getSelectionElement(this.window),i=/ "),this.pasteHTML("
"+e.join("
")+"
");try{this.document.execCommand("insertText",!1,"\n")}catch(k){}for(e=h.querySelectorAll("a,p,div,br"),d=0;d"+d.innerHTML+"":e.innerHTML=d.innerHTML,d.parentNode.replaceChild(e,d);for(f=a.querySelectorAll("span"),c=0;c#",contentFA:' ',key:"k"},this.name="anchor",this.hasForm=!0}a.prototype={formSaveLabel:"✓",formCloseLabel:"×",handleClick:function(a){a.preventDefault(),a.stopPropagation();var c=f.getSelectedParentElement(b.getSelectionRange(this.base.options.ownerDocument));return c.tagName&&"a"===c.tagName.toLowerCase()?this.base.execAction("unlink"):(this.isDisplayed()||this.showForm(),!1)},handleKeydown:function(a){var c=String.fromCharCode(a.which||a.keyCode).toLowerCase();this.options.key===c&&b.isMetaCtrlKey(a)&&(a.preventDefault(),a.stopPropagation(),this.handleClick(a))},getForm:function(){return this.form||(this.form=this.createForm()),this.form},getTemplate:function(){var a=[' '];return a.push('',"fontawesome"===this.base.options.buttonLabels?' ':this.formSaveLabel," "),a.push('',"fontawesome"===this.base.options.buttonLabels?' ':this.formCloseLabel," "),this.base.options.anchorTarget&&a.push(' ',"",this.base.options.anchorInputCheckboxLabel," "),this.base.options.anchorButton&&a.push(' ',"Button "),a.join("")},isDisplayed:function(){return"block"===this.getForm().style.display},hideForm:function(){this.getForm().style.display="none",
+this.getInput().value=""},showForm:function(a){var b=this.getInput();this.base.saveSelection(),this.base.hideToolbarDefaultActions(),this.getForm().style.display="block",this.base.setToolbarPosition(),b.value=a||"",b.focus()},deactivate:function(){return this.form?(this.form.parentNode&&this.form.parentNode.removeChild(this.form),void delete this.form):!1},getFormOpts:function(){var a=this.getForm().querySelector(".medium-editor-toolbar-anchor-target"),b=this.getForm().querySelector(".medium-editor-toolbar-anchor-button"),c={url:this.getInput().value};return this.base.options.checkLinkFormat&&(c.url=this.checkLinkFormat(c.url)),a&&a.checked?c.target="_blank":c.target="_self",b&&b.checked&&(c.buttonClass=this.base.options.anchorButtonClass),c},doFormSave:function(){var a=this.getFormOpts();this.completeFormSave(a)},completeFormSave:function(a){this.base.restoreSelection(),this.base.createLink(a),this.base.checkSelection()},checkLinkFormat:function(a){var b=/^(https?|ftps?|rtmpt?):\/\/|mailto:/;return(b.test(a)?"":"http://")+a},doFormCancel:function(){this.base.restoreSelection(),this.base.checkSelection()},attachFormEvents:function(a){var b=a.querySelector(".medium-editor-toolbar-close"),c=a.querySelector(".medium-editor-toolbar-save"),d=a.querySelector(".medium-editor-toolbar-input");this.base.on(a,"click",this.handleFormClick.bind(this)),this.base.on(d,"keyup",this.handleTextboxKeyup.bind(this)),this.base.on(b,"click",this.handleCloseClick.bind(this)),this.base.on(c,"click",this.handleSaveClick.bind(this),!0)},createForm:function(){var a=this.base.options.ownerDocument,b=a.createElement("div");return b.className="medium-editor-toolbar-form",b.id="medium-editor-toolbar-form-anchor-"+this.base.id,b.innerHTML=this.getTemplate(),this.attachFormEvents(b),b},getInput:function(){return this.getForm().querySelector("input.medium-editor-toolbar-input")},handleTextboxKeyup:function(a){return a.keyCode===b.keyCode.ENTER?(a.preventDefault(),void this.doFormSave()):void(a.keyCode===b.keyCode.ESCAPE&&(a.preventDefault(),this.doFormCancel()))},handleFormClick:function(a){a.stopPropagation()},handleSaveClick:function(a){a.preventDefault(),this.doFormSave()},handleCloseClick:function(a){a.preventDefault(),this.doFormCancel()}},j=b.derives(h,a)}();var k;!function(){k=function(){this.parent=!0,this.name="anchor-preview"},k.prototype={previewValueSelector:"a",init:function(a){this.base=a,this.anchorPreview=this.createPreview(),this.base.options.elementsContainer.appendChild(this.anchorPreview),this.attachToEditables()},getPreviewElement:function(){return this.anchorPreview},createPreview:function(){var a=this.base.options.ownerDocument.createElement("div");return a.id="medium-editor-anchor-preview-"+this.base.id,a.className="medium-editor-anchor-preview",a.innerHTML=this.getTemplate(),this.base.on(a,"click",this.handleClick.bind(this)),a},getTemplate:function(){return''},deactivate:function(){this.anchorPreview&&(this.anchorPreview.parentNode&&this.anchorPreview.parentNode.removeChild(this.anchorPreview),delete this.anchorPreview)},hidePreview:function(){this.anchorPreview.classList.remove("medium-editor-anchor-preview-active"),this.activeAnchor=null},showPreview:function(a){return this.anchorPreview.classList.contains("medium-editor-anchor-preview-active")||a.getAttribute("data-disable-preview")?!0:(this.previewValueSelector&&(this.anchorPreview.querySelector(this.previewValueSelector).textContent=a.attributes.href.value,this.anchorPreview.querySelector(this.previewValueSelector).href=a.attributes.href.value),this.anchorPreview.classList.add("medium-toolbar-arrow-over"),this.anchorPreview.classList.remove("medium-toolbar-arrow-under"),this.anchorPreview.classList.contains("medium-editor-anchor-preview-active")||this.anchorPreview.classList.add("medium-editor-anchor-preview-active"),this.activeAnchor=a,this.positionPreview(),this.attachPreviewHandlers(),this)},positionPreview:function(){var a,b,c=this.anchorPreview.offsetHeight,d=this.activeAnchor.getBoundingClientRect(),e=(d.left+d.right)/2;a=this.anchorPreview.offsetWidth/2,b=this.base.options.diffLeft-a,this.anchorPreview.style.top=Math.round(c+d.bottom-this.base.options.diffTop+this.base.options.contentWindow.pageYOffset-this.anchorPreview.offsetHeight)+"px",a>e?this.anchorPreview.style.left=b+a+"px":this.base.options.contentWindow.innerWidth-ethis.base.options.anchorPreviewHideDelay&&this.detachPreviewHandlers()},detachPreviewHandlers:function(){clearInterval(this.intervalTimer),this.instanceHandlePreviewMouseover&&(this.base.off(this.anchorPreview,"mouseover",this.instanceHandlePreviewMouseover),this.base.off(this.anchorPreview,"mouseout",this.instanceHandlePreviewMouseout),this.activeAnchor&&(this.base.off(this.activeAnchor,"mouseover",this.instanceHandlePreviewMouseover),this.base.off(this.activeAnchor,"mouseout",this.instanceHandlePreviewMouseout))),this.hidePreview(),this.hovering=this.instanceHandlePreviewMouseover=this.instanceHandlePreviewMouseout=null},attachPreviewHandlers:function(){this.lastOver=(new Date).getTime(),this.hovering=!0,this.instanceHandlePreviewMouseover=this.handlePreviewMouseover.bind(this),this.instanceHandlePreviewMouseout=this.handlePreviewMouseout.bind(this),this.intervalTimer=setInterval(this.updatePreview.bind(this),200),this.base.on(this.anchorPreview,"mouseover",this.instanceHandlePreviewMouseover),this.base.on(this.anchorPreview,"mouseout",this.instanceHandlePreviewMouseout),this.base.on(this.activeAnchor,"mouseover",this.instanceHandlePreviewMouseover),this.base.on(this.activeAnchor,"mouseout",this.instanceHandlePreviewMouseout)}}}();var l;!function(){function a(){this.parent=!0,this.options={name:"fontsize",action:"fontSize",aria:"increase/decrease font size",contentDefault:"±",contentFA:' '},this.name="fontsize",this.hasForm=!0}a.prototype={handleClick:function(a){if(a.preventDefault(),a.stopPropagation(),!this.isDisplayed()){var b=this.base.options.ownerDocument.queryCommandValue("fontSize")+"";this.showForm(b)}return!1},getForm:function(){return this.form||(this.form=this.createForm()),this.form},isDisplayed:function(){return"block"===this.getForm().style.display},hideForm:function(){this.getForm().style.display="none",this.getInput().value=""},showForm:function(a){var b=this.getInput();this.base.saveSelection(),this.base.hideToolbarDefaultActions(),this.getForm().style.display="block",this.base.setToolbarPosition(),b.value=a||"",b.focus()},deactivate:function(){return this.form?(this.form.parentNode&&this.form.parentNode.removeChild(this.form),void delete this.form):!1},doFormSave:function(){this.base.restoreSelection(),this.base.checkSelection()},doFormCancel:function(){this.base.restoreSelection(),this.clearFontSize(),this.base.checkSelection()},createForm:function(){var a=this.base.options.ownerDocument,b=a.createElement("div"),c=a.createElement("input"),d=a.createElement("a"),e=a.createElement("a");return b.className="medium-editor-toolbar-form",b.id="medium-editor-toolbar-form-fontsize-"+this.base.id,this.base.on(b,"click",this.handleFormClick.bind(this)),c.setAttribute("type","range"),c.setAttribute("min","1"),c.setAttribute("max","7"),c.className="medium-editor-toolbar-input",b.appendChild(c),this.base.on(c,"change",this.handleSliderChange.bind(this)),e.setAttribute("href","#"),e.className="medium-editor-toobar-save",e.innerHTML="fontawesome"===this.base.options.buttonLabels?' ':"✓",b.appendChild(e),this.base.on(e,"click",this.handleSaveClick.bind(this),!0),d.setAttribute("href","#"),d.className="medium-editor-toobar-close",d.innerHTML="fontawesome"===this.base.options.buttonLabels?' ':"×",b.appendChild(d),this.base.on(d,"click",this.handleCloseClick.bind(this)),b},getInput:function(){return this.getForm().querySelector("input.medium-editor-toolbar-input")},clearFontSize:function(){f.getSelectedElements(this.base.options.ownerDocument).forEach(function(a){"FONT"===a.tagName&&a.hasAttribute("size")&&a.removeAttribute("size")})},handleSliderChange:function(){var a=this.getInput().value;"4"===a?this.clearFontSize():this.base.execAction("fontSize",{size:a})},handleFormClick:function(a){a.stopPropagation()},handleSaveClick:function(a){a.preventDefault(),this.doFormSave()},handleCloseClick:function(a){a.preventDefault(),this.doFormCancel()}},l=b.derives(h,a)}();var m;!function(){m=function(a){this.base=a,this.options=a.options,this.initThrottledMethods()},m.prototype={createToolbar:function(){var a=this.base.options.ownerDocument.createElement("div");return a.id="medium-editor-toolbar-"+this.base.id,a.className="medium-editor-toolbar",this.options.staticToolbar?a.className+=" static-toolbar":a.className+=" stalker-toolbar",a.appendChild(this.createToolbarButtons()),this.base.commands.forEach(function(b){b.hasForm&&a.appendChild(b.getForm())}),this.attachEventHandlers(),a},createToolbarButtons:function(){var a,c,d,e,f=this.base.options.ownerDocument.createElement("ul");return f.id="medium-editor-toolbar-actions"+this.base.id,f.className="medium-editor-toolbar-actions clearfix",f.style.display="block",this.base.options.buttons.forEach(function(d){e=this.base.getExtensionByName(d),"function"==typeof e.getButton&&(c=e.getButton(this.base),a=this.base.options.ownerDocument.createElement("li"),b.isElement(c)?a.appendChild(c):a.innerHTML=c,f.appendChild(a))}.bind(this)),d=f.querySelectorAll("button"),d.length>0&&(d[0].classList.add(this.options.firstButtonClass),d[d.length-1].classList.add(this.options.lastButtonClass)),f},deactivate:function(){this.toolbar&&(this.toolbar.parentNode&&this.toolbar.parentNode.removeChild(this.toolbar),delete this.toolbar)},getToolbarElement:function(){return this.toolbar||(this.toolbar=this.createToolbar()),this.toolbar},getToolbarActionsElement:function(){return this.getToolbarElement().querySelector(".medium-editor-toolbar-actions")},initThrottledMethods:function(){this.throttledPositionToolbar=b.throttle(function(){this.base.isActive&&this.positionToolbarIfShown()}.bind(this))},attachEventHandlers:function(){this.base.subscribe("blur",this.handleBlur.bind(this)),this.base.subscribe("focus",this.handleFocus.bind(this)),this.base.subscribe("editableClick",this.handleEditableClick.bind(this)),this.base.subscribe("editableKeyup",this.handleEditableKeyup.bind(this)),this.base.on(this.options.ownerDocument.documentElement,"mouseup",this.handleDocumentMouseup.bind(this)),this.options.staticToolbar&&this.options.stickyToolbar&&this.base.on(this.options.contentWindow,"scroll",this.handleWindowScroll.bind(this),!0),this.base.on(this.options.contentWindow,"resize",this.handleWindowResize.bind(this))},handleWindowScroll:function(){this.positionToolbarIfShown()},handleWindowResize:function(){this.throttledPositionToolbar()},handleDocumentMouseup:function(a){return a&&a.target&&b.isDescendant(this.getToolbarElement(),a.target)?!1:void this.checkState()},handleEditableClick:function(){setTimeout(function(){this.checkState()}.bind(this),0)},handleEditableKeyup:function(){this.checkState()},handleBlur:function(){clearTimeout(this.hideTimeout),clearTimeout(this.delayShowTimeout),this.hideTimeout=setTimeout(function(){this.hideToolbar()}.bind(this),1)},handleFocus:function(){this.checkState()},isDisplayed:function(){return this.getToolbarElement().classList.contains("medium-editor-toolbar-active")},showToolbar:function(){clearTimeout(this.hideTimeout),this.isDisplayed()||(this.getToolbarElement().classList.add("medium-editor-toolbar-active"),"function"==typeof this.options.onShowToolbar&&this.options.onShowToolbar())},hideToolbar:function(){this.isDisplayed()&&(this.base.commands.forEach(function(a){"function"==typeof a.onHide&&a.onHide()}),this.getToolbarElement().classList.remove("medium-editor-toolbar-active"),"function"==typeof this.options.onHideToolbar&&this.options.onHideToolbar())},isToolbarDefaultActionsDisplayed:function(){return"block"===this.getToolbarActionsElement().style.display},hideToolbarDefaultActions:function(){this.isToolbarDefaultActionsDisplayed()&&(this.getToolbarActionsElement().style.display="none")},showToolbarDefaultActions:function(){this.hideExtensionForms(),this.isToolbarDefaultActionsDisplayed()||(this.getToolbarActionsElement().style.display="block"),this.delayShowTimeout=this.base.delay(function(){this.showToolbar()}.bind(this))},hideExtensionForms:function(){this.base.commands.forEach(function(a){a.hasForm&&a.isDisplayed()&&a.hideForm()})},multipleBlockElementsSelected:function(){var a=f.getSelectionHtml.call(this).replace(/<[\S]+><\/[\S]+>/gim,""),b=a.match(/<(p|h[1-6]|blockquote)[^>]*>/g);return!!b&&b.length>1},modifySelection:function(){var a=this.options.contentWindow.getSelection(),c=a.getRangeAt(0);if(this.options.standardizeSelectionStart&&c.startContainer.nodeValue&&c.startOffset===c.startContainer.nodeValue.length){var d=b.findAdjacentTextNodeWithContent(f.getSelectionElement(this.options.contentWindow),c.startContainer,this.options.ownerDocument);if(d){for(var e=0;0===d.nodeValue.substr(e,1).trim().length;)e+=1;var g=this.options.ownerDocument.createRange();g.setStart(d,e),g.setEnd(c.endContainer,c.endOffset),a.removeAllRanges(),a.addRange(g),c=g}}},checkState:function(){if(!this.base.preventSelectionUpdates){if(!this.getFocusedElement()||f.selectionInContentEditableFalse(this.options.contentWindow))return void this.hideToolbar();var a=f.getSelectionElement(this.options.contentWindow);if(!a||-1===this.base.elements.indexOf(a)||a.getAttribute("data-disable-toolbar"))return void this.hideToolbar();if(this.options.updateOnEmptySelection&&this.options.staticToolbar)return void this.showAndUpdateToolbar();""===this.options.contentWindow.getSelection().toString().trim()||this.options.allowMultiParagraphSelection===!1&&this.multipleBlockElementsSelected()?this.hideToolbar():this.showAndUpdateToolbar()}},getFocusedElement:function(){for(var a=0;ag+a.offsetHeight-i?(e.style.top=g+a.offsetHeight-i+"px",e.classList.remove("sticky-toolbar")):c>g-i?(e.classList.add("sticky-toolbar"),e.style.top="0px"):(e.classList.remove("sticky-toolbar"),e.style.top=g-i+"px"):e.style.top=g-i+"px","left"===this.options.toolbarAlign?b=f.left:"center"===this.options.toolbarAlign?b=h-k:"right"===this.options.toolbarAlign&&(b=f.right-j),0>b?b=0:b+j>d&&(b=d-Math.ceil(j)-1),e.style.left=b+"px"},positionToolbar:function(a){this.getToolbarElement().style.left="0";var b=this.options.contentWindow.innerWidth,c=a.getRangeAt(0),d=c.getBoundingClientRect(),e=(d.left+d.right)/2,f=this.getToolbarElement(),g=f.offsetHeight,h=f.offsetWidth,i=h/2,j=50,k=this.options.diffLeft-i;d.tope?f.style.left=k+i+"px":i>b-e?f.style.left=b+k-i+"px":f.style.left=k+e+"px"}}}();var n;!function(){n=function(a){this.base=a,this.initPlaceholders(),this.attachEventHandlers()},n.prototype={initPlaceholders:function(){this.base.elements.forEach(function(a){this.updatePlaceholder(a)},this)},showPlaceholder:function(a){a&&a.classList.add("medium-editor-placeholder")},hidePlaceholder:function(a){a&&a.classList.remove("medium-editor-placeholder")},updatePlaceholder:function(a){a.querySelector("img")||a.querySelector("blockquote")||""!==a.textContent.replace(/^\s+|\s+$/g,"")?this.hidePlaceholder(a):this.showPlaceholder(a)},attachEventHandlers:function(){this.base.subscribe("blur",this.handleExternalInteraction.bind(this)),this.base.subscribe("editableBlur",this.handleBlur.bind(this)),this.base.subscribe("editableClick",this.handleHidePlaceholderEvent.bind(this)),this.base.subscribe("editableKeypress",this.handleHidePlaceholderEvent.bind(this)),this.base.subscribe("editablePaste",this.handleHidePlaceholderEvent.bind(this))},handleHidePlaceholderEvent:function(a,b){this.hidePlaceholder(b)},handleBlur:function(a,b){this.updatePlaceholder(b)},handleExternalInteraction:function(){this.initPlaceholders()}}}();var o;return function(){o={paste:i}}(),function(){function i(a,c){if(this.options.disableReturn||c.getAttribute("data-disable-return"))a.preventDefault();else if(this.options.disableDoubleReturn||c.getAttribute("data-disable-double-return")){var d=b.getSelectionStart(this.options.ownerDocument);d&&""===d.textContent.trim()&&a.preventDefault()}}function p(a){var c=b.getSelectionStart(this.options.ownerDocument),d=c&&c.tagName.toLowerCase();"pre"===d&&(a.preventDefault(),b.insertHTMLCommand(this.options.ownerDocument," ")),b.isListItem(c)&&(a.preventDefault(),a.shiftKey?this.options.ownerDocument.execCommand("outdent",!1,null):this.options.ownerDocument.execCommand("indent",!1,null))}function q(a){var c,d,e,g=b.getSelectionStart(this.options.ownerDocument),h=g.tagName.toLowerCase(),i=/^(\s+| )?$/i,j=/h\d/i;(a.which===b.keyCode.BACKSPACE||a.which===b.keyCode.ENTER)&&g.previousElementSibling&&j.test(h)&&0===f.getCaretOffsets(g).left?a.which===b.keyCode.BACKSPACE&&i.test(g.previousElementSibling.innerHTML)?(g.previousElementSibling.parentNode.removeChild(g.previousElementSibling),a.preventDefault()):a.which===b.keyCode.ENTER&&(e=this.options.ownerDocument.createElement("p"),e.innerHTML=" ",g.previousElementSibling.parentNode.insertBefore(e,g),a.preventDefault()):a.which===b.keyCode.DELETE&&g.nextElementSibling&&g.previousElementSibling&&!j.test(h)&&i.test(g.innerHTML)&&j.test(g.nextElementSibling.tagName)?(c=this.options.ownerDocument.createRange(),d=this.options.ownerDocument.getSelection(),c.setStart(g.nextElementSibling,0),c.collapse(!0),d.removeAllRanges(),d.addRange(c),g.previousElementSibling.parentNode.removeChild(g),a.preventDefault()):a.which!==b.keyCode.BACKSPACE||"li"!==h||!i.test(g.innerHTML)||g.previousElementSibling||g.parentElement.previousElementSibling||"li"!==g.nextElementSibling.tagName.toLowerCase()||(e=this.options.ownerDocument.createElement("p"),e.innerHTML=" ",g.parentElement.parentElement.insertBefore(e,g.parentElement),c=this.options.ownerDocument.createRange(),d=this.options.ownerDocument.getSelection(),c.setStart(e,0),c.collapse(!0),d.removeAllRanges(),d.addRange(c),g.parentElement.removeChild(g),a.preventDefault())}function r(a){var b="medium-editor-dragover";a.preventDefault(),a.dataTransfer.dropEffect="copy","dragover"===a.type?a.target.classList.add(b):"dragleave"===a.type&&a.target.classList.remove(b)}function s(a){var c,d="medium-editor-dragover";a.preventDefault(),a.stopPropagation(),a.dataTransfer.files&&(c=Array.prototype.slice.call(a.dataTransfer.files,0),c.some(function(a){if(a.type.match("image")){var c,d;c=new FileReader,c.readAsDataURL(a),d="medium-img-"+ +new Date,b.insertHTMLCommand(this.options.ownerDocument,' '),c.onload=function(){var a=this.options.ownerDocument.getElementById(d);a&&(a.removeAttribute("id"),a.removeAttribute("class"),a.src=c.result)}.bind(this)}}.bind(this))),a.target.classList.remove(d)}function t(a){var c,d=b.getSelectionStart(this.options.ownerDocument);d&&(d.getAttribute("data-medium-element")&&0===d.children.length&&this.options.ownerDocument.execCommand("formatBlock",!1,"p"),a.which!==b.keyCode.ENTER||b.isListItem(d)||(c=d.tagName.toLowerCase(),"a"===c?this.options.ownerDocument.execCommand("unlink",!1,null):a.shiftKey||/h\d/.test(c)||this.options.ownerDocument.execCommand("formatBlock",!1,"p")))}function u(a){a||(a=[]),"string"==typeof a&&(a=this.options.ownerDocument.querySelectorAll(a)),b.isElement(a)&&(a=[a]);var c=Array.prototype.slice.apply(a);this.elements=[],c.forEach(function(a){this.elements.push("textarea"===a.tagName.toLowerCase()?x.call(this,a):a)},this)}function v(a,b,c){return a.parent&&(a.base=c),"function"==typeof a.init&&a.init(c),a.name||(a.name=b),a}function w(){var a,b=!1;if(this.options.disableAnchorPreview)return!1;if(this.options.extensions["anchor-preview"])return!1;if(this.options.disableToolbar)return!1;for(a=0;a0&&(a=f.getRangeAt(0),c=a.cloneRange(),this.elements.some(function(c,d){return c===a.startContainer||b.isDescendant(c,a.startContainer)?(g=d,!0):!1}),g>-1&&(c.selectNodeContents(this.elements[g]),c.setEnd(a.startContainer,a.startOffset),d=c.toString().length,e={start:d,end:d+a.toString().length,editableElementIndex:g})),null!==e&&0===e.editableElementIndex&&delete e.editableElementIndex,e},saveSelection:function(){this.selectionState=this.exportSelection()},importSelection:function(a){if(a){var b,c,d,e,f=void 0===a.editableElementIndex?0:a.editableElementIndex,g={
+editableElementIndex:f,start:a.start,end:a.end},h=this.elements[g.editableElementIndex],i=0,j=this.options.ownerDocument.createRange(),k=[h],l=!1,m=!1;for(j.setStart(h,0),j.collapse(!0),b=k.pop();!m&&b;){if(3===b.nodeType)e=i+b.length,!l&&g.start>=i&&g.start<=e&&(j.setStart(b,g.start-i),l=!0),l&&g.end>=i&&g.end<=e&&(j.setEnd(b,g.end-i),m=!0),i=e;else for(c=b.childNodes.length-1;c>=0;)k.push(b.childNodes[c]),c-=1;m||(b=k.pop())}d=this.options.contentWindow.getSelection(),d.removeAllRanges(),d.addRange(j)}},restoreSelection:function(){this.importSelection(this.selectionState)},createLink:function(a){var c,d;if(a.url&&a.url.trim().length>0&&(this.options.ownerDocument.execCommand("createLink",!1,a.url),(this.options.targetBlank||"_blank"===a.target)&&b.setTargetBlank(b.getSelectionStart(this.options.ownerDocument)),a.buttonClass&&b.addClassToAnchors(b.getSelectionStart(this.options.ownerDocument),a.buttonClass)),this.options.targetBlank||"_blank"===a.target||a.buttonClass)for(c=this.options.ownerDocument.createEvent("HTMLEvents"),c.initEvent("input",!0,!0,this.options.contentWindow),d=0;d
+
+
+ Quill Editor
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ = partial('/partials/sample-html') ?>
+
+
+
+
\ No newline at end of file
diff --git a/views/partials/appcache.php b/views/partials/appcache.php
new file mode 100644
index 0000000..4fa1f13
--- /dev/null
+++ b/views/partials/appcache.php
@@ -0,0 +1,22 @@
+CACHE MANIFEST
+
+# v1
+
+/editor
+/editor/style.css
+/editor/medium-editor/css/medium-editor.min.css
+/editor/medium-editor/css/themes/default.min.css
+/editor/medium-editor/css/medium-editor-insert-plugin.min.css
+/editor/medium-editor/css/medium-editor-insert-plugin-frontend.min.css
+/editor/font-awesome/css/font-awesome.css
+/editor/jquery-1.11.3.min.js
+/editor/jquery-ui-1.11.4.custom/jquery-ui.min.js
+/editor/jquery.fileupload.js
+/editor/jquery.iframetransport.js
+/editor/handlebars.min.js
+/editor/medium-editor/js/medium-editor.min.js
+/editor/medium-editor/js/medium-editor-insert-plugin.min.js
+/editor/localforage/localforage.js
+
+NETWORK:
+*