├── .gitignore ├── README.md ├── example ├── .meteor │ ├── .gitignore │ ├── packages │ └── release ├── example.html ├── example.js ├── packages │ └── .gitignore ├── smart.json └── smart.lock ├── lib ├── address │ ├── address.css │ └── address.js ├── bootstrap-editable │ ├── css │ │ └── bootstrap-editable.css │ ├── img │ │ ├── clear.png │ │ └── loading.gif │ └── js │ │ └── bootstrap-editable.js └── wysihtml5 │ ├── bootstrap-wysihtml5-0.0.2 │ ├── bootstrap-wysihtml5-0.0.2.css │ ├── bootstrap-wysihtml5-0.0.2.js │ ├── wysihtml5-0.3.0.js │ └── wysiwyg-color.css │ └── wysihtml5.js ├── package.js └── path-override.css /.gitignore: -------------------------------------------------------------------------------- 1 | versions.json 2 | 3 | lib-cov 4 | *.seed 5 | *.log 6 | *.csv 7 | *.dat 8 | *.out 9 | *.pid 10 | *.gz 11 | 12 | pids 13 | logs 14 | results 15 | 16 | npm-debug.log 17 | 18 | *.sublime-workspace 19 | .build* 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | meteor-x-editable 2 | ================= 3 | 4 | The [x-editable](http://vitalets.github.io/x-editable/) in-place editor with Twitter Bootstrap, repackaged for Meteor. 5 | 6 | # Install 7 | 8 | ``` 9 | meteor add natestrauser:x-editable-bootstrap 10 | ``` 11 | 12 | **NOTE**: The latest branch uses the Bootstrap 3 build of x-editable. If you are still using Bootstrap 2 and on Meteor 0.8.3 or earlier, install v1.4.6.3 using Meteorite instead of the latest. 13 | 14 | textarea example 15 | ---------------- 16 | 17 | #### template 18 | 19 |

{{textAreaContent}}

20 | 21 | #### rendered callback 22 | 23 | The short answer: 24 | 25 | $('#textArea.editable').editable({ 26 | success: function(response, newValue) { 27 | 28 | }}); 29 | 30 | The long answer: trying to use x-editable properly on Meteor 0.8 with reactive updates can get interesting. If there is a lot of concurrency in your editing, you will want to consult the information and links in [this StackOverflow post](http://stackoverflow.com/a/23144211/586086). 31 | 32 | version history 33 | --------------- 34 | #### 1.5.1 35 | 36 | - Updated to use BS3 build of x-editable 1.5.1. 37 | 38 | #### 1.4.6.2 39 | 40 | - Added example and updated readme to reflect operation under meteor 0.8.0+ (syntax is more simple with blaze) 41 | -------------------------------------------------------------------------------- /example/.meteor/.gitignore: -------------------------------------------------------------------------------- 1 | local 2 | -------------------------------------------------------------------------------- /example/.meteor/packages: -------------------------------------------------------------------------------- 1 | # Meteor packages used by this project, one per line. 2 | # 3 | # 'meteor add' and 'meteor remove' will edit this file for you, 4 | # but you can also edit it by hand. 5 | 6 | standard-app-packages 7 | autopublish 8 | insecure 9 | bootstrap 10 | x-editable-bootstrap 11 | -------------------------------------------------------------------------------- /example/.meteor/release: -------------------------------------------------------------------------------- 1 | 0.8.0 2 | -------------------------------------------------------------------------------- /example/example.html: -------------------------------------------------------------------------------- 1 | 2 | example 3 | 4 | 5 | 6 |
7 |
8 | {{> editable}} 9 |
10 |
11 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /example/example.js: -------------------------------------------------------------------------------- 1 | if (Meteor.isClient) { 2 | Session.setDefault('textAreaContent', "Some text area content that is editable on click"); 3 | 4 | Template.editable.helpers({ 5 | 'textAreaContent': function () { 6 | return Session.get('textAreaContent'); 7 | } 8 | }); 9 | 10 | Template.editable.rendered = function(){ 11 | $('#textArea.editable').editable({ 12 | placement: "auto top", 13 | success: function(response, newValue) { 14 | console.log('set new value to ' + newValue); 15 | Session.set('textAreaContent', newValue); 16 | }}); 17 | 18 | }; 19 | } 20 | 21 | if (Meteor.isServer) { 22 | Meteor.startup(function () { 23 | // code to run on server at startup 24 | }); 25 | } 26 | -------------------------------------------------------------------------------- /example/packages/.gitignore: -------------------------------------------------------------------------------- 1 | /x-editable-bootstrap 2 | /bootstrap-3 3 | -------------------------------------------------------------------------------- /example/smart.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": { 3 | "x-editable-bootstrap": { 4 | "path": "../" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /example/smart.lock: -------------------------------------------------------------------------------- 1 | { 2 | "meteor": {}, 3 | "dependencies": { 4 | "basePackages": { 5 | "x-editable-bootstrap": { 6 | "path": ".." 7 | } 8 | }, 9 | "packages": { 10 | "x-editable-bootstrap": { 11 | "path": ".." 12 | }, 13 | "bootstrap-3": { 14 | "git": "https://github.com/mangasocial/meteor-bootstrap-3.git", 15 | "tag": "v3.1.1-1", 16 | "commit": "63dd38968828bb8963636df93e9a1c45e2dfe67e" 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/address/address.css: -------------------------------------------------------------------------------- 1 | .editable-address { 2 | display: block; 3 | margin-bottom: 5px; 4 | } 5 | 6 | .editable-address span { 7 | width: 70px; 8 | display: inline-block; 9 | } -------------------------------------------------------------------------------- /lib/address/address.js: -------------------------------------------------------------------------------- 1 | /** 2 | Address editable input. 3 | Internally value stored as {city: "Moscow", street: "Lenina", building: "15"} 4 | 5 | @class address 6 | @extends abstractinput 7 | @final 8 | @example 9 | awesome 10 | 23 | **/ 24 | (function ($) { 25 | "use strict"; 26 | 27 | var Address = function (options) { 28 | this.init('address', options, Address.defaults); 29 | }; 30 | 31 | //inherit from Abstract input 32 | $.fn.editableutils.inherit(Address, $.fn.editabletypes.abstractinput); 33 | 34 | $.extend(Address.prototype, { 35 | /** 36 | Renders input from tpl 37 | 38 | @method render() 39 | **/ 40 | render: function() { 41 | this.$input = this.$tpl.find('input'); 42 | }, 43 | 44 | /** 45 | Default method to show value in element. Can be overwritten by display option. 46 | 47 | @method value2html(value, element) 48 | **/ 49 | value2html: function(value, element) { 50 | if(!value) { 51 | $(element).empty(); 52 | return; 53 | } 54 | var html = $('
').text(value.city).html() + ', ' + $('
').text(value.street).html() + ' st., bld. ' + $('
').text(value.building).html(); 55 | $(element).html(html); 56 | }, 57 | 58 | /** 59 | Gets value from element's html 60 | 61 | @method html2value(html) 62 | **/ 63 | html2value: function(html) { 64 | /* 65 | you may write parsing method to get value by element's html 66 | e.g. "Moscow, st. Lenina, bld. 15" => {city: "Moscow", street: "Lenina", building: "15"} 67 | but for complex structures it's not recommended. 68 | Better set value directly via javascript, e.g. 69 | editable({ 70 | value: { 71 | city: "Moscow", 72 | street: "Lenina", 73 | building: "15" 74 | } 75 | }); 76 | */ 77 | return null; 78 | }, 79 | 80 | /** 81 | Converts value to string. 82 | It is used in internal comparing (not for sending to server). 83 | 84 | @method value2str(value) 85 | **/ 86 | value2str: function(value) { 87 | var str = ''; 88 | if(value) { 89 | for(var k in value) { 90 | str = str + k + ':' + value[k] + ';'; 91 | } 92 | } 93 | return str; 94 | }, 95 | 96 | /* 97 | Converts string to value. Used for reading value from 'data-value' attribute. 98 | 99 | @method str2value(str) 100 | */ 101 | str2value: function(str) { 102 | /* 103 | this is mainly for parsing value defined in data-value attribute. 104 | If you will always set value by javascript, no need to overwrite it 105 | */ 106 | return str; 107 | }, 108 | 109 | /** 110 | Sets value of input. 111 | 112 | @method value2input(value) 113 | @param {mixed} value 114 | **/ 115 | value2input: function(value) { 116 | if(!value) { 117 | return; 118 | } 119 | this.$input.filter('[name="city"]').val(value.city); 120 | this.$input.filter('[name="street"]').val(value.street); 121 | this.$input.filter('[name="building"]').val(value.building); 122 | }, 123 | 124 | /** 125 | Returns value of input. 126 | 127 | @method input2value() 128 | **/ 129 | input2value: function() { 130 | return { 131 | city: this.$input.filter('[name="city"]').val(), 132 | street: this.$input.filter('[name="street"]').val(), 133 | building: this.$input.filter('[name="building"]').val() 134 | }; 135 | }, 136 | 137 | /** 138 | Activates input: sets focus on the first field. 139 | 140 | @method activate() 141 | **/ 142 | activate: function() { 143 | this.$input.filter('[name="city"]').focus(); 144 | }, 145 | 146 | /** 147 | Attaches handler to submit form in case of 'showbuttons=false' mode 148 | 149 | @method autosubmit() 150 | **/ 151 | autosubmit: function() { 152 | this.$input.keydown(function (e) { 153 | if (e.which === 13) { 154 | $(this).closest('form').submit(); 155 | } 156 | }); 157 | } 158 | }); 159 | 160 | Address.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 161 | tpl: '
'+ 162 | '
'+ 163 | '
', 164 | 165 | inputclass: '' 166 | }); 167 | 168 | $.fn.editabletypes.address = Address; 169 | 170 | }(window.jQuery)); -------------------------------------------------------------------------------- /lib/bootstrap-editable/css/bootstrap-editable.css: -------------------------------------------------------------------------------- 1 | /*! X-editable - v1.5.1 2 | * In-place editing with Twitter Bootstrap, jQuery UI or pure jQuery 3 | * http://github.com/vitalets/x-editable 4 | * Copyright (c) 2013 Vitaliy Potapov; Licensed MIT */ 5 | .editableform { 6 | margin-bottom: 0; /* overwrites bootstrap margin */ 7 | } 8 | 9 | .editableform .control-group { 10 | margin-bottom: 0; /* overwrites bootstrap margin */ 11 | white-space: nowrap; /* prevent wrapping buttons on new line */ 12 | line-height: 20px; /* overwriting bootstrap line-height. See #133 */ 13 | } 14 | 15 | /* 16 | BS3 width:1005 for inputs breaks editable form in popup 17 | See: https://github.com/vitalets/x-editable/issues/393 18 | */ 19 | .editableform .form-control { 20 | width: auto; 21 | } 22 | 23 | .editable-buttons { 24 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 25 | vertical-align: top; 26 | margin-left: 7px; 27 | /* inline-block emulation for IE7*/ 28 | zoom: 1; 29 | *display: inline; 30 | } 31 | 32 | .editable-buttons.editable-buttons-bottom { 33 | display: block; 34 | margin-top: 7px; 35 | margin-left: 0; 36 | } 37 | 38 | .editable-input { 39 | vertical-align: top; 40 | display: inline-block; /* should be inline to take effect of parent's white-space: nowrap */ 41 | width: auto; /* bootstrap-responsive has width: 100% that breakes layout */ 42 | white-space: normal; /* reset white-space decalred in parent*/ 43 | /* display-inline emulation for IE7*/ 44 | zoom: 1; 45 | *display: inline; 46 | } 47 | 48 | .editable-buttons .editable-cancel { 49 | margin-left: 7px; 50 | } 51 | 52 | /*for jquery-ui buttons need set height to look more pretty*/ 53 | .editable-buttons button.ui-button-icon-only { 54 | height: 24px; 55 | width: 30px; 56 | } 57 | 58 | .editableform-loading { 59 | background: url('../img/loading.gif') center center no-repeat; 60 | height: 25px; 61 | width: auto; 62 | min-width: 25px; 63 | } 64 | 65 | .editable-inline .editableform-loading { 66 | background-position: left 5px; 67 | } 68 | 69 | .editable-error-block { 70 | max-width: 300px; 71 | margin: 5px 0 0 0; 72 | width: auto; 73 | white-space: normal; 74 | } 75 | 76 | /*add padding for jquery ui*/ 77 | .editable-error-block.ui-state-error { 78 | padding: 3px; 79 | } 80 | 81 | .editable-error { 82 | color: red; 83 | } 84 | 85 | /* ---- For specific types ---- */ 86 | 87 | .editableform .editable-date { 88 | padding: 0; 89 | margin: 0; 90 | float: left; 91 | } 92 | 93 | /* move datepicker icon to center of add-on button. See https://github.com/vitalets/x-editable/issues/183 */ 94 | .editable-inline .add-on .icon-th { 95 | margin-top: 3px; 96 | margin-left: 1px; 97 | } 98 | 99 | 100 | /* checklist vertical alignment */ 101 | .editable-checklist label input[type="checkbox"], 102 | .editable-checklist label span { 103 | vertical-align: middle; 104 | margin: 0; 105 | } 106 | 107 | .editable-checklist label { 108 | white-space: nowrap; 109 | } 110 | 111 | /* set exact width of textarea to fit buttons toolbar */ 112 | .editable-wysihtml5 { 113 | width: 566px; 114 | height: 250px; 115 | } 116 | 117 | /* clear button shown as link in date inputs */ 118 | .editable-clear { 119 | clear: both; 120 | font-size: 0.9em; 121 | text-decoration: none; 122 | text-align: right; 123 | } 124 | 125 | /* IOS-style clear button for text inputs */ 126 | .editable-clear-x { 127 | background: url('../img/clear.png') center center no-repeat; 128 | display: block; 129 | width: 13px; 130 | height: 13px; 131 | position: absolute; 132 | opacity: 0.6; 133 | z-index: 100; 134 | 135 | top: 50%; 136 | right: 6px; 137 | margin-top: -6px; 138 | 139 | } 140 | 141 | .editable-clear-x:hover { 142 | opacity: 1; 143 | } 144 | 145 | .editable-pre-wrapped { 146 | white-space: pre-wrap; 147 | } 148 | .editable-container.editable-popup { 149 | max-width: none !important; /* without this rule poshytip/tooltip does not stretch */ 150 | } 151 | 152 | .editable-container.popover { 153 | width: auto; /* without this rule popover does not stretch */ 154 | } 155 | 156 | .editable-container.editable-inline { 157 | display: inline-block; 158 | vertical-align: middle; 159 | width: auto; 160 | /* inline-block emulation for IE7*/ 161 | zoom: 1; 162 | *display: inline; 163 | } 164 | 165 | .editable-container.ui-widget { 166 | font-size: inherit; /* jqueryui widget font 1.1em too big, overwrite it */ 167 | z-index: 9990; /* should be less than select2 dropdown z-index to close dropdown first when click */ 168 | } 169 | .editable-click, 170 | a.editable-click, 171 | a.editable-click:hover { 172 | text-decoration: none; 173 | border-bottom: dashed 1px #0088cc; 174 | } 175 | 176 | .editable-click.editable-disabled, 177 | a.editable-click.editable-disabled, 178 | a.editable-click.editable-disabled:hover { 179 | color: #585858; 180 | cursor: default; 181 | border-bottom: none; 182 | } 183 | 184 | .editable-empty, .editable-empty:hover, .editable-empty:focus{ 185 | font-style: italic; 186 | color: #DD1144; 187 | /* border-bottom: none; */ 188 | text-decoration: none; 189 | } 190 | 191 | .editable-unsaved { 192 | font-weight: bold; 193 | } 194 | 195 | .editable-unsaved:after { 196 | /* content: '*'*/ 197 | } 198 | 199 | .editable-bg-transition { 200 | -webkit-transition: background-color 1400ms ease-out; 201 | -moz-transition: background-color 1400ms ease-out; 202 | -o-transition: background-color 1400ms ease-out; 203 | -ms-transition: background-color 1400ms ease-out; 204 | transition: background-color 1400ms ease-out; 205 | } 206 | 207 | /*see https://github.com/vitalets/x-editable/issues/139 */ 208 | .form-horizontal .editable 209 | { 210 | padding-top: 5px; 211 | display:inline-block; 212 | } 213 | 214 | 215 | /*! 216 | * Datepicker for Bootstrap 217 | * 218 | * Copyright 2012 Stefan Petre 219 | * Improvements by Andrew Rowls 220 | * Licensed under the Apache License v2.0 221 | * http://www.apache.org/licenses/LICENSE-2.0 222 | * 223 | */ 224 | .datepicker { 225 | padding: 4px; 226 | -webkit-border-radius: 4px; 227 | -moz-border-radius: 4px; 228 | border-radius: 4px; 229 | direction: ltr; 230 | /*.dow { 231 | border-top: 1px solid #ddd !important; 232 | }*/ 233 | 234 | } 235 | .datepicker-inline { 236 | width: 220px; 237 | } 238 | .datepicker.datepicker-rtl { 239 | direction: rtl; 240 | } 241 | .datepicker.datepicker-rtl table tr td span { 242 | float: right; 243 | } 244 | .datepicker-dropdown { 245 | top: 0; 246 | left: 0; 247 | } 248 | .datepicker-dropdown:before { 249 | content: ''; 250 | display: inline-block; 251 | border-left: 7px solid transparent; 252 | border-right: 7px solid transparent; 253 | border-bottom: 7px solid #ccc; 254 | border-bottom-color: rgba(0, 0, 0, 0.2); 255 | position: absolute; 256 | top: -7px; 257 | left: 6px; 258 | } 259 | .datepicker-dropdown:after { 260 | content: ''; 261 | display: inline-block; 262 | border-left: 6px solid transparent; 263 | border-right: 6px solid transparent; 264 | border-bottom: 6px solid #ffffff; 265 | position: absolute; 266 | top: -6px; 267 | left: 7px; 268 | } 269 | .datepicker > div { 270 | display: none; 271 | } 272 | .datepicker.days div.datepicker-days { 273 | display: block; 274 | } 275 | .datepicker.months div.datepicker-months { 276 | display: block; 277 | } 278 | .datepicker.years div.datepicker-years { 279 | display: block; 280 | } 281 | .datepicker table { 282 | margin: 0; 283 | } 284 | .datepicker td, 285 | .datepicker th { 286 | text-align: center; 287 | width: 20px; 288 | height: 20px; 289 | -webkit-border-radius: 4px; 290 | -moz-border-radius: 4px; 291 | border-radius: 4px; 292 | border: none; 293 | } 294 | .table-striped .datepicker table tr td, 295 | .table-striped .datepicker table tr th { 296 | background-color: transparent; 297 | } 298 | .datepicker table tr td.day:hover { 299 | background: #eeeeee; 300 | cursor: pointer; 301 | } 302 | .datepicker table tr td.old, 303 | .datepicker table tr td.new { 304 | color: #999999; 305 | } 306 | .datepicker table tr td.disabled, 307 | .datepicker table tr td.disabled:hover { 308 | background: none; 309 | color: #999999; 310 | cursor: default; 311 | } 312 | .datepicker table tr td.today, 313 | .datepicker table tr td.today:hover, 314 | .datepicker table tr td.today.disabled, 315 | .datepicker table tr td.today.disabled:hover { 316 | background-color: #fde19a; 317 | background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); 318 | background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); 319 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); 320 | background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); 321 | background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); 322 | background-image: linear-gradient(top, #fdd49a, #fdf59a); 323 | background-repeat: repeat-x; 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); 325 | border-color: #fdf59a #fdf59a #fbed50; 326 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 327 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 328 | color: #000; 329 | } 330 | .datepicker table tr td.today:hover, 331 | .datepicker table tr td.today:hover:hover, 332 | .datepicker table tr td.today.disabled:hover, 333 | .datepicker table tr td.today.disabled:hover:hover, 334 | .datepicker table tr td.today:active, 335 | .datepicker table tr td.today:hover:active, 336 | .datepicker table tr td.today.disabled:active, 337 | .datepicker table tr td.today.disabled:hover:active, 338 | .datepicker table tr td.today.active, 339 | .datepicker table tr td.today:hover.active, 340 | .datepicker table tr td.today.disabled.active, 341 | .datepicker table tr td.today.disabled:hover.active, 342 | .datepicker table tr td.today.disabled, 343 | .datepicker table tr td.today:hover.disabled, 344 | .datepicker table tr td.today.disabled.disabled, 345 | .datepicker table tr td.today.disabled:hover.disabled, 346 | .datepicker table tr td.today[disabled], 347 | .datepicker table tr td.today:hover[disabled], 348 | .datepicker table tr td.today.disabled[disabled], 349 | .datepicker table tr td.today.disabled:hover[disabled] { 350 | background-color: #fdf59a; 351 | } 352 | .datepicker table tr td.today:active, 353 | .datepicker table tr td.today:hover:active, 354 | .datepicker table tr td.today.disabled:active, 355 | .datepicker table tr td.today.disabled:hover:active, 356 | .datepicker table tr td.today.active, 357 | .datepicker table tr td.today:hover.active, 358 | .datepicker table tr td.today.disabled.active, 359 | .datepicker table tr td.today.disabled:hover.active { 360 | background-color: #fbf069 \9; 361 | } 362 | .datepicker table tr td.today:hover:hover { 363 | color: #000; 364 | } 365 | .datepicker table tr td.today.active:hover { 366 | color: #fff; 367 | } 368 | .datepicker table tr td.range, 369 | .datepicker table tr td.range:hover, 370 | .datepicker table tr td.range.disabled, 371 | .datepicker table tr td.range.disabled:hover { 372 | background: #eeeeee; 373 | -webkit-border-radius: 0; 374 | -moz-border-radius: 0; 375 | border-radius: 0; 376 | } 377 | .datepicker table tr td.range.today, 378 | .datepicker table tr td.range.today:hover, 379 | .datepicker table tr td.range.today.disabled, 380 | .datepicker table tr td.range.today.disabled:hover { 381 | background-color: #f3d17a; 382 | background-image: -moz-linear-gradient(top, #f3c17a, #f3e97a); 383 | background-image: -ms-linear-gradient(top, #f3c17a, #f3e97a); 384 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f3c17a), to(#f3e97a)); 385 | background-image: -webkit-linear-gradient(top, #f3c17a, #f3e97a); 386 | background-image: -o-linear-gradient(top, #f3c17a, #f3e97a); 387 | background-image: linear-gradient(top, #f3c17a, #f3e97a); 388 | background-repeat: repeat-x; 389 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f3c17a', endColorstr='#f3e97a', GradientType=0); 390 | border-color: #f3e97a #f3e97a #edde34; 391 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 392 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 393 | -webkit-border-radius: 0; 394 | -moz-border-radius: 0; 395 | border-radius: 0; 396 | } 397 | .datepicker table tr td.range.today:hover, 398 | .datepicker table tr td.range.today:hover:hover, 399 | .datepicker table tr td.range.today.disabled:hover, 400 | .datepicker table tr td.range.today.disabled:hover:hover, 401 | .datepicker table tr td.range.today:active, 402 | .datepicker table tr td.range.today:hover:active, 403 | .datepicker table tr td.range.today.disabled:active, 404 | .datepicker table tr td.range.today.disabled:hover:active, 405 | .datepicker table tr td.range.today.active, 406 | .datepicker table tr td.range.today:hover.active, 407 | .datepicker table tr td.range.today.disabled.active, 408 | .datepicker table tr td.range.today.disabled:hover.active, 409 | .datepicker table tr td.range.today.disabled, 410 | .datepicker table tr td.range.today:hover.disabled, 411 | .datepicker table tr td.range.today.disabled.disabled, 412 | .datepicker table tr td.range.today.disabled:hover.disabled, 413 | .datepicker table tr td.range.today[disabled], 414 | .datepicker table tr td.range.today:hover[disabled], 415 | .datepicker table tr td.range.today.disabled[disabled], 416 | .datepicker table tr td.range.today.disabled:hover[disabled] { 417 | background-color: #f3e97a; 418 | } 419 | .datepicker table tr td.range.today:active, 420 | .datepicker table tr td.range.today:hover:active, 421 | .datepicker table tr td.range.today.disabled:active, 422 | .datepicker table tr td.range.today.disabled:hover:active, 423 | .datepicker table tr td.range.today.active, 424 | .datepicker table tr td.range.today:hover.active, 425 | .datepicker table tr td.range.today.disabled.active, 426 | .datepicker table tr td.range.today.disabled:hover.active { 427 | background-color: #efe24b \9; 428 | } 429 | .datepicker table tr td.selected, 430 | .datepicker table tr td.selected:hover, 431 | .datepicker table tr td.selected.disabled, 432 | .datepicker table tr td.selected.disabled:hover { 433 | background-color: #9e9e9e; 434 | background-image: -moz-linear-gradient(top, #b3b3b3, #808080); 435 | background-image: -ms-linear-gradient(top, #b3b3b3, #808080); 436 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b3b3b3), to(#808080)); 437 | background-image: -webkit-linear-gradient(top, #b3b3b3, #808080); 438 | background-image: -o-linear-gradient(top, #b3b3b3, #808080); 439 | background-image: linear-gradient(top, #b3b3b3, #808080); 440 | background-repeat: repeat-x; 441 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#b3b3b3', endColorstr='#808080', GradientType=0); 442 | border-color: #808080 #808080 #595959; 443 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 444 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 445 | color: #fff; 446 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 447 | } 448 | .datepicker table tr td.selected:hover, 449 | .datepicker table tr td.selected:hover:hover, 450 | .datepicker table tr td.selected.disabled:hover, 451 | .datepicker table tr td.selected.disabled:hover:hover, 452 | .datepicker table tr td.selected:active, 453 | .datepicker table tr td.selected:hover:active, 454 | .datepicker table tr td.selected.disabled:active, 455 | .datepicker table tr td.selected.disabled:hover:active, 456 | .datepicker table tr td.selected.active, 457 | .datepicker table tr td.selected:hover.active, 458 | .datepicker table tr td.selected.disabled.active, 459 | .datepicker table tr td.selected.disabled:hover.active, 460 | .datepicker table tr td.selected.disabled, 461 | .datepicker table tr td.selected:hover.disabled, 462 | .datepicker table tr td.selected.disabled.disabled, 463 | .datepicker table tr td.selected.disabled:hover.disabled, 464 | .datepicker table tr td.selected[disabled], 465 | .datepicker table tr td.selected:hover[disabled], 466 | .datepicker table tr td.selected.disabled[disabled], 467 | .datepicker table tr td.selected.disabled:hover[disabled] { 468 | background-color: #808080; 469 | } 470 | .datepicker table tr td.selected:active, 471 | .datepicker table tr td.selected:hover:active, 472 | .datepicker table tr td.selected.disabled:active, 473 | .datepicker table tr td.selected.disabled:hover:active, 474 | .datepicker table tr td.selected.active, 475 | .datepicker table tr td.selected:hover.active, 476 | .datepicker table tr td.selected.disabled.active, 477 | .datepicker table tr td.selected.disabled:hover.active { 478 | background-color: #666666 \9; 479 | } 480 | .datepicker table tr td.active, 481 | .datepicker table tr td.active:hover, 482 | .datepicker table tr td.active.disabled, 483 | .datepicker table tr td.active.disabled:hover { 484 | background-color: #006dcc; 485 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc); 486 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc); 487 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 488 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); 489 | background-image: -o-linear-gradient(top, #0088cc, #0044cc); 490 | background-image: linear-gradient(top, #0088cc, #0044cc); 491 | background-repeat: repeat-x; 492 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 493 | border-color: #0044cc #0044cc #002a80; 494 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 495 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 496 | color: #fff; 497 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 498 | } 499 | .datepicker table tr td.active:hover, 500 | .datepicker table tr td.active:hover:hover, 501 | .datepicker table tr td.active.disabled:hover, 502 | .datepicker table tr td.active.disabled:hover:hover, 503 | .datepicker table tr td.active:active, 504 | .datepicker table tr td.active:hover:active, 505 | .datepicker table tr td.active.disabled:active, 506 | .datepicker table tr td.active.disabled:hover:active, 507 | .datepicker table tr td.active.active, 508 | .datepicker table tr td.active:hover.active, 509 | .datepicker table tr td.active.disabled.active, 510 | .datepicker table tr td.active.disabled:hover.active, 511 | .datepicker table tr td.active.disabled, 512 | .datepicker table tr td.active:hover.disabled, 513 | .datepicker table tr td.active.disabled.disabled, 514 | .datepicker table tr td.active.disabled:hover.disabled, 515 | .datepicker table tr td.active[disabled], 516 | .datepicker table tr td.active:hover[disabled], 517 | .datepicker table tr td.active.disabled[disabled], 518 | .datepicker table tr td.active.disabled:hover[disabled] { 519 | background-color: #0044cc; 520 | } 521 | .datepicker table tr td.active:active, 522 | .datepicker table tr td.active:hover:active, 523 | .datepicker table tr td.active.disabled:active, 524 | .datepicker table tr td.active.disabled:hover:active, 525 | .datepicker table tr td.active.active, 526 | .datepicker table tr td.active:hover.active, 527 | .datepicker table tr td.active.disabled.active, 528 | .datepicker table tr td.active.disabled:hover.active { 529 | background-color: #003399 \9; 530 | } 531 | .datepicker table tr td span { 532 | display: block; 533 | width: 23%; 534 | height: 54px; 535 | line-height: 54px; 536 | float: left; 537 | margin: 1%; 538 | cursor: pointer; 539 | -webkit-border-radius: 4px; 540 | -moz-border-radius: 4px; 541 | border-radius: 4px; 542 | } 543 | .datepicker table tr td span:hover { 544 | background: #eeeeee; 545 | } 546 | .datepicker table tr td span.disabled, 547 | .datepicker table tr td span.disabled:hover { 548 | background: none; 549 | color: #999999; 550 | cursor: default; 551 | } 552 | .datepicker table tr td span.active, 553 | .datepicker table tr td span.active:hover, 554 | .datepicker table tr td span.active.disabled, 555 | .datepicker table tr td span.active.disabled:hover { 556 | background-color: #006dcc; 557 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc); 558 | background-image: -ms-linear-gradient(top, #0088cc, #0044cc); 559 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); 560 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); 561 | background-image: -o-linear-gradient(top, #0088cc, #0044cc); 562 | background-image: linear-gradient(top, #0088cc, #0044cc); 563 | background-repeat: repeat-x; 564 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); 565 | border-color: #0044cc #0044cc #002a80; 566 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); 567 | filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); 568 | color: #fff; 569 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); 570 | } 571 | .datepicker table tr td span.active:hover, 572 | .datepicker table tr td span.active:hover:hover, 573 | .datepicker table tr td span.active.disabled:hover, 574 | .datepicker table tr td span.active.disabled:hover:hover, 575 | .datepicker table tr td span.active:active, 576 | .datepicker table tr td span.active:hover:active, 577 | .datepicker table tr td span.active.disabled:active, 578 | .datepicker table tr td span.active.disabled:hover:active, 579 | .datepicker table tr td span.active.active, 580 | .datepicker table tr td span.active:hover.active, 581 | .datepicker table tr td span.active.disabled.active, 582 | .datepicker table tr td span.active.disabled:hover.active, 583 | .datepicker table tr td span.active.disabled, 584 | .datepicker table tr td span.active:hover.disabled, 585 | .datepicker table tr td span.active.disabled.disabled, 586 | .datepicker table tr td span.active.disabled:hover.disabled, 587 | .datepicker table tr td span.active[disabled], 588 | .datepicker table tr td span.active:hover[disabled], 589 | .datepicker table tr td span.active.disabled[disabled], 590 | .datepicker table tr td span.active.disabled:hover[disabled] { 591 | background-color: #0044cc; 592 | } 593 | .datepicker table tr td span.active:active, 594 | .datepicker table tr td span.active:hover:active, 595 | .datepicker table tr td span.active.disabled:active, 596 | .datepicker table tr td span.active.disabled:hover:active, 597 | .datepicker table tr td span.active.active, 598 | .datepicker table tr td span.active:hover.active, 599 | .datepicker table tr td span.active.disabled.active, 600 | .datepicker table tr td span.active.disabled:hover.active { 601 | background-color: #003399 \9; 602 | } 603 | .datepicker table tr td span.old, 604 | .datepicker table tr td span.new { 605 | color: #999999; 606 | } 607 | .datepicker th.datepicker-switch { 608 | width: 145px; 609 | } 610 | .datepicker thead tr:first-child th, 611 | .datepicker tfoot tr th { 612 | cursor: pointer; 613 | } 614 | .datepicker thead tr:first-child th:hover, 615 | .datepicker tfoot tr th:hover { 616 | background: #eeeeee; 617 | } 618 | .datepicker .cw { 619 | font-size: 10px; 620 | width: 12px; 621 | padding: 0 2px 0 5px; 622 | vertical-align: middle; 623 | } 624 | .datepicker thead tr:first-child th.cw { 625 | cursor: default; 626 | background-color: transparent; 627 | } 628 | .input-append.date .add-on i, 629 | .input-prepend.date .add-on i { 630 | display: block; 631 | cursor: pointer; 632 | width: 16px; 633 | height: 16px; 634 | } 635 | .input-daterange input { 636 | text-align: center; 637 | } 638 | .input-daterange input:first-child { 639 | -webkit-border-radius: 3px 0 0 3px; 640 | -moz-border-radius: 3px 0 0 3px; 641 | border-radius: 3px 0 0 3px; 642 | } 643 | .input-daterange input:last-child { 644 | -webkit-border-radius: 0 3px 3px 0; 645 | -moz-border-radius: 0 3px 3px 0; 646 | border-radius: 0 3px 3px 0; 647 | } 648 | .input-daterange .add-on { 649 | display: inline-block; 650 | width: auto; 651 | min-width: 16px; 652 | height: 18px; 653 | padding: 4px 5px; 654 | font-weight: normal; 655 | line-height: 18px; 656 | text-align: center; 657 | text-shadow: 0 1px 0 #ffffff; 658 | vertical-align: middle; 659 | background-color: #eeeeee; 660 | border: 1px solid #ccc; 661 | margin-left: -5px; 662 | margin-right: -5px; 663 | } 664 | -------------------------------------------------------------------------------- /lib/bootstrap-editable/img/clear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nate-strauser/meteor-x-editable-bootstrap/0762d54fd0d3e04572ec8d2ed6dc7f4f5c835369/lib/bootstrap-editable/img/clear.png -------------------------------------------------------------------------------- /lib/bootstrap-editable/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nate-strauser/meteor-x-editable-bootstrap/0762d54fd0d3e04572ec8d2ed6dc7f4f5c835369/lib/bootstrap-editable/img/loading.gif -------------------------------------------------------------------------------- /lib/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.css: -------------------------------------------------------------------------------- 1 | ul.wysihtml5-toolbar { 2 | margin: 0; 3 | padding: 0; 4 | display: block; 5 | } 6 | 7 | ul.wysihtml5-toolbar::after { 8 | clear: both; 9 | display: table; 10 | content: ""; 11 | } 12 | 13 | ul.wysihtml5-toolbar > li { 14 | float: left; 15 | display: list-item; 16 | list-style: none; 17 | margin: 0 5px 10px 0; 18 | } 19 | 20 | ul.wysihtml5-toolbar a[data-wysihtml5-command=bold] { 21 | font-weight: bold; 22 | } 23 | 24 | ul.wysihtml5-toolbar a[data-wysihtml5-command=italic] { 25 | font-style: italic; 26 | } 27 | 28 | ul.wysihtml5-toolbar a[data-wysihtml5-command=underline] { 29 | text-decoration: underline; 30 | } 31 | 32 | ul.wysihtml5-toolbar a.btn.wysihtml5-command-active { 33 | background-image: none; 34 | -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 35 | -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 36 | box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05); 37 | background-color: #E6E6E6; 38 | background-color: #D9D9D9; 39 | outline: 0; 40 | } 41 | 42 | ul.wysihtml5-commands-disabled .dropdown-menu { 43 | display: none !important; 44 | } 45 | 46 | ul.wysihtml5-toolbar div.wysihtml5-colors { 47 | display:block; 48 | width: 50px; 49 | height: 20px; 50 | margin-top: 2px; 51 | margin-left: 5px; 52 | position: absolute; 53 | pointer-events: none; 54 | } 55 | 56 | ul.wysihtml5-toolbar a.wysihtml5-colors-title { 57 | padding-left: 70px; 58 | } 59 | 60 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="black"] { 61 | background: black !important; 62 | } 63 | 64 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="silver"] { 65 | background: silver !important; 66 | } 67 | 68 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="gray"] { 69 | background: gray !important; 70 | } 71 | 72 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="maroon"] { 73 | background: maroon !important; 74 | } 75 | 76 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="red"] { 77 | background: red !important; 78 | } 79 | 80 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="purple"] { 81 | background: purple !important; 82 | } 83 | 84 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="green"] { 85 | background: green !important; 86 | } 87 | 88 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="olive"] { 89 | background: olive !important; 90 | } 91 | 92 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="navy"] { 93 | background: navy !important; 94 | } 95 | 96 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="blue"] { 97 | background: blue !important; 98 | } 99 | 100 | ul.wysihtml5-toolbar div[data-wysihtml5-command-value="orange"] { 101 | background: orange !important; 102 | } 103 | -------------------------------------------------------------------------------- /lib/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.js: -------------------------------------------------------------------------------- 1 | !function($, wysi) { 2 | "use strict"; 3 | 4 | var tpl = { 5 | "font-styles": function(locale, options) { 6 | var size = (options && options.size) ? ' btn-'+options.size : ''; 7 | return ""; 18 | }, 19 | 20 | "emphasis": function(locale, options) { 21 | var size = (options && options.size) ? ' btn-'+options.size : ''; 22 | return "
  • " + 23 | "" + 28 | "
  • "; 29 | }, 30 | 31 | "lists": function(locale, options) { 32 | var size = (options && options.size) ? ' btn-'+options.size : ''; 33 | return "
  • " + 34 | "
    " + 35 | "" + 36 | "" + 37 | "" + 38 | "" + 39 | "
    " + 40 | "
  • "; 41 | }, 42 | 43 | "link": function(locale, options) { 44 | var size = (options && options.size) ? ' btn-'+options.size : ''; 45 | return "
  • " + 46 | "" + 59 | "" + 60 | "
  • "; 61 | }, 62 | 63 | "image": function(locale, options) { 64 | var size = (options && options.size) ? ' btn-'+options.size : ''; 65 | return "
  • " + 66 | "" + 79 | "" + 80 | "
  • "; 81 | }, 82 | 83 | "html": function(locale, options) { 84 | var size = (options && options.size) ? ' btn-'+options.size : ''; 85 | return "
  • " + 86 | "
    " + 87 | "" + 88 | "
    " + 89 | "
  • "; 90 | }, 91 | 92 | "color": function(locale, options) { 93 | var size = (options && options.size) ? ' btn-'+options.size : ''; 94 | return ""; 112 | } 113 | }; 114 | 115 | var templates = function(key, locale, options) { 116 | return tpl[key](locale, options); 117 | }; 118 | 119 | 120 | var Wysihtml5 = function(el, options) { 121 | this.el = el; 122 | var toolbarOpts = options || defaultOptions; 123 | for(var t in toolbarOpts.customTemplates) { 124 | tpl[t] = toolbarOpts.customTemplates[t]; 125 | } 126 | this.toolbar = this.createToolbar(el, toolbarOpts); 127 | this.editor = this.createEditor(options); 128 | 129 | window.editor = this.editor; 130 | 131 | $('iframe.wysihtml5-sandbox').each(function(i, el){ 132 | $(el.contentWindow).off('focus.wysihtml5').on({ 133 | 'focus.wysihtml5' : function(){ 134 | $('li.dropdown').removeClass('open'); 135 | } 136 | }); 137 | }); 138 | }; 139 | 140 | Wysihtml5.prototype = { 141 | 142 | constructor: Wysihtml5, 143 | 144 | createEditor: function(options) { 145 | options = options || {}; 146 | 147 | // Add the toolbar to a clone of the options object so multiple instances 148 | // of the WYISYWG don't break because "toolbar" is already defined 149 | options = $.extend(true, {}, options); 150 | options.toolbar = this.toolbar[0]; 151 | 152 | var editor = new wysi.Editor(this.el[0], options); 153 | 154 | if(options && options.events) { 155 | for(var eventName in options.events) { 156 | editor.on(eventName, options.events[eventName]); 157 | } 158 | } 159 | return editor; 160 | }, 161 | 162 | createToolbar: function(el, options) { 163 | var self = this; 164 | var toolbar = $("
      ", { 165 | 'class' : "wysihtml5-toolbar", 166 | 'style': "display:none" 167 | }); 168 | var culture = options.locale || defaultOptions.locale || "en"; 169 | for(var key in defaultOptions) { 170 | var value = false; 171 | 172 | if(options[key] !== undefined) { 173 | if(options[key] === true) { 174 | value = true; 175 | } 176 | } else { 177 | value = defaultOptions[key]; 178 | } 179 | 180 | if(value === true) { 181 | toolbar.append(templates(key, locale[culture], options)); 182 | 183 | if(key === "html") { 184 | this.initHtml(toolbar); 185 | } 186 | 187 | if(key === "link") { 188 | this.initInsertLink(toolbar); 189 | } 190 | 191 | if(key === "image") { 192 | this.initInsertImage(toolbar); 193 | } 194 | } 195 | } 196 | 197 | if(options.toolbar) { 198 | for(key in options.toolbar) { 199 | toolbar.append(options.toolbar[key]); 200 | } 201 | } 202 | 203 | toolbar.find("a[data-wysihtml5-command='formatBlock']").click(function(e) { 204 | var target = e.target || e.srcElement; 205 | var el = $(target); 206 | self.toolbar.find('.current-font').text(el.html()); 207 | }); 208 | 209 | toolbar.find("a[data-wysihtml5-command='foreColor']").click(function(e) { 210 | var target = e.target || e.srcElement; 211 | var el = $(target); 212 | self.toolbar.find('.current-color').text(el.html()); 213 | }); 214 | 215 | this.el.before(toolbar); 216 | 217 | return toolbar; 218 | }, 219 | 220 | initHtml: function(toolbar) { 221 | var changeViewSelector = "a[data-wysihtml5-action='change_view']"; 222 | toolbar.find(changeViewSelector).click(function(e) { 223 | toolbar.find('a.btn').not(changeViewSelector).toggleClass('disabled'); 224 | }); 225 | }, 226 | 227 | initInsertImage: function(toolbar) { 228 | var self = this; 229 | var insertImageModal = toolbar.find('.bootstrap-wysihtml5-insert-image-modal'); 230 | var urlInput = insertImageModal.find('.bootstrap-wysihtml5-insert-image-url'); 231 | var insertButton = insertImageModal.find('a.btn-primary'); 232 | var initialValue = urlInput.val(); 233 | var caretBookmark; 234 | 235 | var insertImage = function() { 236 | var url = urlInput.val(); 237 | urlInput.val(initialValue); 238 | self.editor.currentView.element.focus(); 239 | if (caretBookmark) { 240 | self.editor.composer.selection.setBookmark(caretBookmark); 241 | caretBookmark = null; 242 | } 243 | self.editor.composer.commands.exec("insertImage", url); 244 | }; 245 | 246 | urlInput.keypress(function(e) { 247 | if(e.which == 13) { 248 | insertImage(); 249 | insertImageModal.modal('hide'); 250 | } 251 | }); 252 | 253 | insertButton.click(insertImage); 254 | 255 | insertImageModal.on('shown', function() { 256 | urlInput.focus(); 257 | }); 258 | 259 | insertImageModal.on('hide', function() { 260 | self.editor.currentView.element.focus(); 261 | }); 262 | 263 | toolbar.find('a[data-wysihtml5-command=insertImage]').click(function() { 264 | var activeButton = $(this).hasClass("wysihtml5-command-active"); 265 | 266 | if (!activeButton) { 267 | self.editor.currentView.element.focus(false); 268 | caretBookmark = self.editor.composer.selection.getBookmark(); 269 | insertImageModal.appendTo('body').modal('show'); 270 | insertImageModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) { 271 | e.stopPropagation(); 272 | }); 273 | return false; 274 | } 275 | else { 276 | return true; 277 | } 278 | }); 279 | }, 280 | 281 | initInsertLink: function(toolbar) { 282 | var self = this; 283 | var insertLinkModal = toolbar.find('.bootstrap-wysihtml5-insert-link-modal'); 284 | var urlInput = insertLinkModal.find('.bootstrap-wysihtml5-insert-link-url'); 285 | var insertButton = insertLinkModal.find('a.btn-primary'); 286 | var initialValue = urlInput.val(); 287 | var caretBookmark; 288 | 289 | var insertLink = function() { 290 | var url = urlInput.val(); 291 | urlInput.val(initialValue); 292 | self.editor.currentView.element.focus(); 293 | if (caretBookmark) { 294 | self.editor.composer.selection.setBookmark(caretBookmark); 295 | caretBookmark = null; 296 | } 297 | self.editor.composer.commands.exec("createLink", { 298 | href: url, 299 | target: "_blank", 300 | rel: "nofollow" 301 | }); 302 | }; 303 | var pressedEnter = false; 304 | 305 | urlInput.keypress(function(e) { 306 | if(e.which == 13) { 307 | insertLink(); 308 | insertLinkModal.modal('hide'); 309 | } 310 | }); 311 | 312 | insertButton.click(insertLink); 313 | 314 | insertLinkModal.on('shown', function() { 315 | urlInput.focus(); 316 | }); 317 | 318 | insertLinkModal.on('hide', function() { 319 | self.editor.currentView.element.focus(); 320 | }); 321 | 322 | toolbar.find('a[data-wysihtml5-command=createLink]').click(function() { 323 | var activeButton = $(this).hasClass("wysihtml5-command-active"); 324 | 325 | if (!activeButton) { 326 | self.editor.currentView.element.focus(false); 327 | caretBookmark = self.editor.composer.selection.getBookmark(); 328 | insertLinkModal.appendTo('body').modal('show'); 329 | insertLinkModal.on('click.dismiss.modal', '[data-dismiss="modal"]', function(e) { 330 | e.stopPropagation(); 331 | }); 332 | return false; 333 | } 334 | else { 335 | return true; 336 | } 337 | }); 338 | } 339 | }; 340 | 341 | // these define our public api 342 | var methods = { 343 | resetDefaults: function() { 344 | $.fn.wysihtml5.defaultOptions = $.extend(true, {}, $.fn.wysihtml5.defaultOptionsCache); 345 | }, 346 | bypassDefaults: function(options) { 347 | return this.each(function () { 348 | var $this = $(this); 349 | $this.data('wysihtml5', new Wysihtml5($this, options)); 350 | }); 351 | }, 352 | shallowExtend: function (options) { 353 | var settings = $.extend({}, $.fn.wysihtml5.defaultOptions, options || {}); 354 | var that = this; 355 | return methods.bypassDefaults.apply(that, [settings]); 356 | }, 357 | deepExtend: function(options) { 358 | var settings = $.extend(true, {}, $.fn.wysihtml5.defaultOptions, options || {}); 359 | var that = this; 360 | return methods.bypassDefaults.apply(that, [settings]); 361 | }, 362 | init: function(options) { 363 | var that = this; 364 | return methods.shallowExtend.apply(that, [options]); 365 | } 366 | }; 367 | 368 | $.fn.wysihtml5 = function ( method ) { 369 | if ( methods[method] ) { 370 | return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); 371 | } else if ( typeof method === 'object' || ! method ) { 372 | return methods.init.apply( this, arguments ); 373 | } else { 374 | $.error( 'Method ' + method + ' does not exist on jQuery.wysihtml5' ); 375 | } 376 | }; 377 | 378 | $.fn.wysihtml5.Constructor = Wysihtml5; 379 | 380 | var defaultOptions = $.fn.wysihtml5.defaultOptions = { 381 | "font-styles": true, 382 | "color": false, 383 | "emphasis": true, 384 | "lists": true, 385 | "html": false, 386 | "link": true, 387 | "image": true, 388 | events: {}, 389 | parserRules: { 390 | classes: { 391 | // (path_to_project/lib/css/wysiwyg-color.css) 392 | "wysiwyg-color-silver" : 1, 393 | "wysiwyg-color-gray" : 1, 394 | "wysiwyg-color-white" : 1, 395 | "wysiwyg-color-maroon" : 1, 396 | "wysiwyg-color-red" : 1, 397 | "wysiwyg-color-purple" : 1, 398 | "wysiwyg-color-fuchsia" : 1, 399 | "wysiwyg-color-green" : 1, 400 | "wysiwyg-color-lime" : 1, 401 | "wysiwyg-color-olive" : 1, 402 | "wysiwyg-color-yellow" : 1, 403 | "wysiwyg-color-navy" : 1, 404 | "wysiwyg-color-blue" : 1, 405 | "wysiwyg-color-teal" : 1, 406 | "wysiwyg-color-aqua" : 1, 407 | "wysiwyg-color-orange" : 1 408 | }, 409 | tags: { 410 | "b": {}, 411 | "i": {}, 412 | "br": {}, 413 | "ol": {}, 414 | "ul": {}, 415 | "li": {}, 416 | "h1": {}, 417 | "h2": {}, 418 | "h3": {}, 419 | "blockquote": {}, 420 | "u": 1, 421 | "img": { 422 | "check_attributes": { 423 | "width": "numbers", 424 | "alt": "alt", 425 | "src": "url", 426 | "height": "numbers" 427 | } 428 | }, 429 | "a": { 430 | set_attributes: { 431 | target: "_blank", 432 | rel: "nofollow" 433 | }, 434 | check_attributes: { 435 | href: "url" // important to avoid XSS 436 | } 437 | }, 438 | "span": 1, 439 | "div": 1, 440 | // to allow save and edit files with code tag hacks 441 | "code": 1, 442 | "pre": 1 443 | } 444 | }, 445 | stylesheets: ["./lib/css/wysiwyg-color.css"], // (path_to_project/lib/css/wysiwyg-color.css) 446 | locale: "en" 447 | }; 448 | 449 | if (typeof $.fn.wysihtml5.defaultOptionsCache === 'undefined') { 450 | $.fn.wysihtml5.defaultOptionsCache = $.extend(true, {}, $.fn.wysihtml5.defaultOptions); 451 | } 452 | 453 | var locale = $.fn.wysihtml5.locale = { 454 | en: { 455 | font_styles: { 456 | normal: "Normal text", 457 | h1: "Heading 1", 458 | h2: "Heading 2", 459 | h3: "Heading 3" 460 | }, 461 | emphasis: { 462 | bold: "Bold", 463 | italic: "Italic", 464 | underline: "Underline" 465 | }, 466 | lists: { 467 | unordered: "Unordered list", 468 | ordered: "Ordered list", 469 | outdent: "Outdent", 470 | indent: "Indent" 471 | }, 472 | link: { 473 | insert: "Insert link", 474 | cancel: "Cancel" 475 | }, 476 | image: { 477 | insert: "Insert image", 478 | cancel: "Cancel" 479 | }, 480 | html: { 481 | edit: "Edit HTML" 482 | }, 483 | colours: { 484 | black: "Black", 485 | silver: "Silver", 486 | gray: "Grey", 487 | maroon: "Maroon", 488 | red: "Red", 489 | purple: "Purple", 490 | green: "Green", 491 | olive: "Olive", 492 | navy: "Navy", 493 | blue: "Blue", 494 | orange: "Orange" 495 | } 496 | } 497 | }; 498 | 499 | }(jQuery, wysihtml5); 500 | -------------------------------------------------------------------------------- /lib/wysihtml5/bootstrap-wysihtml5-0.0.2/wysiwyg-color.css: -------------------------------------------------------------------------------- 1 | .wysiwyg-color-black { 2 | color: black; 3 | } 4 | 5 | .wysiwyg-color-silver { 6 | color: silver; 7 | } 8 | 9 | .wysiwyg-color-gray { 10 | color: gray; 11 | } 12 | 13 | .wysiwyg-color-white { 14 | color: white; 15 | } 16 | 17 | .wysiwyg-color-maroon { 18 | color: maroon; 19 | } 20 | 21 | .wysiwyg-color-red { 22 | color: red; 23 | } 24 | 25 | .wysiwyg-color-purple { 26 | color: purple; 27 | } 28 | 29 | .wysiwyg-color-fuchsia { 30 | color: fuchsia; 31 | } 32 | 33 | .wysiwyg-color-green { 34 | color: green; 35 | } 36 | 37 | .wysiwyg-color-lime { 38 | color: lime; 39 | } 40 | 41 | .wysiwyg-color-olive { 42 | color: olive; 43 | } 44 | 45 | .wysiwyg-color-yellow { 46 | color: yellow; 47 | } 48 | 49 | .wysiwyg-color-navy { 50 | color: navy; 51 | } 52 | 53 | .wysiwyg-color-blue { 54 | color: blue; 55 | } 56 | 57 | .wysiwyg-color-teal { 58 | color: teal; 59 | } 60 | 61 | .wysiwyg-color-aqua { 62 | color: aqua; 63 | } 64 | 65 | .wysiwyg-color-orange { 66 | color: orange; 67 | } -------------------------------------------------------------------------------- /lib/wysihtml5/wysihtml5.js: -------------------------------------------------------------------------------- 1 | /** 2 | Bootstrap wysihtml5 editor. Based on [bootstrap-wysihtml5](https://github.com/jhollingworth/bootstrap-wysihtml5). 3 | You should include **manually** distributives of `wysihtml5` and `bootstrap-wysihtml5`: 4 | 5 | 6 | 7 | 8 | 9 | And also include `wysihtml5.js` from `inputs-ext` directory of x-editable: 10 | 11 | 12 | 13 | **Note:** It's better to use fresh bootstrap-wysihtml5 from it's [master branch](https://github.com/jhollingworth/bootstrap-wysihtml5/tree/master/src) as there is update for correct image insertion. 14 | 15 | @class wysihtml5 16 | @extends abstractinput 17 | @final 18 | @since 1.4.0 19 | @example 20 |

      awesome

      comment!
      21 | 29 | **/ 30 | (function ($) { 31 | "use strict"; 32 | 33 | var Wysihtml5 = function (options) { 34 | this.init('wysihtml5', options, Wysihtml5.defaults); 35 | 36 | //extend wysihtml5 manually as $.extend not recursive 37 | this.options.wysihtml5 = $.extend({}, Wysihtml5.defaults.wysihtml5, options.wysihtml5); 38 | }; 39 | 40 | $.fn.editableutils.inherit(Wysihtml5, $.fn.editabletypes.abstractinput); 41 | 42 | $.extend(Wysihtml5.prototype, { 43 | render: function () { 44 | var deferred = $.Deferred(), 45 | msieOld; 46 | 47 | //generate unique id as it required for wysihtml5 48 | this.$input.attr('id', 'textarea_'+(new Date()).getTime()); 49 | 50 | this.setClass(); 51 | this.setAttr('placeholder'); 52 | 53 | //resolve deffered when widget loaded 54 | $.extend(this.options.wysihtml5, { 55 | events: { 56 | load: function() { 57 | deferred.resolve(); 58 | } 59 | } 60 | }); 61 | 62 | this.$input.wysihtml5(this.options.wysihtml5); 63 | 64 | /* 65 | In IE8 wysihtml5 iframe stays on the same line with buttons toolbar (inside popover). 66 | The only solution I found is to add
      . If you fine better way, please send PR. 67 | */ 68 | msieOld = /msie\s*(8|7|6)/.test(navigator.userAgent.toLowerCase()); 69 | if(msieOld) { 70 | this.$input.before('

      '); 71 | } 72 | 73 | return deferred.promise(); 74 | }, 75 | 76 | value2html: function(value, element) { 77 | $(element).html(value); 78 | }, 79 | 80 | html2value: function(html) { 81 | return html; 82 | }, 83 | 84 | value2input: function(value) { 85 | this.$input.data("wysihtml5").editor.setValue(value, true); 86 | }, 87 | 88 | activate: function() { 89 | this.$input.data("wysihtml5").editor.focus(); 90 | }, 91 | 92 | isEmpty: function($element) { 93 | if($.trim($element.html()) === '') { 94 | return true; 95 | } else if($.trim($element.text()) !== '') { 96 | return false; 97 | } else { 98 | //e.g. '', '
      ', '

      ' 99 | return !$element.height() || !$element.width(); 100 | } 101 | } 102 | }); 103 | 104 | Wysihtml5.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { 105 | /** 106 | @property tpl 107 | @default 108 | **/ 109 | tpl:'', 110 | /** 111 | @property inputclass 112 | @default editable-wysihtml5 113 | **/ 114 | inputclass: 'editable-wysihtml5', 115 | /** 116 | Placeholder attribute of input. Shown when input is empty. 117 | 118 | @property placeholder 119 | @type string 120 | @default null 121 | **/ 122 | placeholder: null, 123 | /** 124 | Wysihtml5 default options. 125 | See https://github.com/jhollingworth/bootstrap-wysihtml5#options 126 | 127 | @property wysihtml5 128 | @type object 129 | @default {stylesheets: false} 130 | **/ 131 | wysihtml5: { 132 | stylesheets: false //see https://github.com/jhollingworth/bootstrap-wysihtml5/issues/183 133 | } 134 | }); 135 | 136 | $.fn.editabletypes.wysihtml5 = Wysihtml5; 137 | 138 | }(window.jQuery)); 139 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name: "natestrauser:x-editable-bootstrap", 3 | summary: "Latest version of X-Editable for Bootstrap with wysihtml5 rich text editor", 4 | version: "1.5.2_4", 5 | git: "https://github.com/nate-strauser/meteor-x-editable-bootstrap.git" 6 | }); 7 | 8 | Package.on_use(function (api){ 9 | api.versionsFrom("1.2.0.1"); 10 | // Package needs jQuery 11 | api.use('jquery'); 12 | 13 | // This depends on BS3 JS libraries, including popovers. 14 | // Need to make sure bootstrap 3 is loaded first, or errors will ensue 15 | // https://github.com/vitalets/x-editable/issues/395 16 | api.use("twbs:bootstrap@3.3.5", "client", { weak: true }); 17 | api.use("nemo64:bootstrap@3.3.5_2", "client", { weak: true }); 18 | 19 | // Add FontAwesome for button icons 20 | api.use("fortawesome:fontawesome@4.4.0", "client", { weak: true }); 21 | 22 | //x-editable 23 | api.addFiles('lib/bootstrap-editable/css/bootstrap-editable.css', 'client'); 24 | api.addFiles('lib/bootstrap-editable/js/bootstrap-editable.js', 'client', {bare:true}); 25 | 26 | api.addAssets('lib/bootstrap-editable/img/clear.png', 'client'); 27 | api.addAssets('lib/bootstrap-editable/img/loading.gif', 'client'); 28 | 29 | //address 30 | api.addFiles('lib/address/address.css', 'client'); 31 | api.addFiles('lib/address/address.js', 'client', {bare:true}); 32 | 33 | //wysihtml5 34 | api.addFiles('lib/wysihtml5/wysihtml5.js', 'client', {bare:true}); 35 | api.addFiles('lib/wysihtml5/bootstrap-wysihtml5-0.0.2/wysiwyg-color.css', 'client'); 36 | api.addFiles('lib/wysihtml5/bootstrap-wysihtml5-0.0.2/wysihtml5-0.3.0.js', 'client', {bare:true}); 37 | api.addFiles('lib/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.css', 'client'); 38 | api.addFiles('lib/wysihtml5/bootstrap-wysihtml5-0.0.2/bootstrap-wysihtml5-0.0.2.js', 'client', {bare:true}); 39 | 40 | //override image paths 41 | api.addFiles('path-override.css', 'client'); 42 | }); 43 | -------------------------------------------------------------------------------- /path-override.css: -------------------------------------------------------------------------------- 1 | .editableform-loading { 2 | background-image: url('/packages/natestrauser_x-editable-bootstrap/lib/bootstrap-editable/img/loading.gif'); 3 | } 4 | 5 | .editable-clear-x { 6 | background-image: url('/packages/natestrauser_x-editable-bootstrap/lib/bootstrap-editable/img/clear.png'); 7 | } 8 | --------------------------------------------------------------------------------