| 1 |
(function ($, exports) { |
| 2 |
|
| 3 |
$(document).ready(function () { |
| 4 |
|
| 5 |
/** |
| 6 |
* A TinyMCE plugin which handles the rendering of grid shortcodes |
| 7 |
* Docs to consider: |
| 8 |
* Manager: https://www.tinymce.com/docs/api/tinymce/tinymce.editormanager |
| 9 |
* Events: https://www.tinymce.com/docs/api/tinymce/tinymce.editor/#events |
| 10 |
*/ |
| 11 |
tinymce.PluginManager.add('gridable', function (editor, url) { |
| 12 |
var toolbar, |
| 13 |
l10n = gridable_params.l10n, |
| 14 |
gridable_resizing = false, |
| 15 |
xStart, |
| 16 |
xLast, |
| 17 |
xEnd, |
| 18 |
nextWidth, |
| 19 |
prevWidth, |
| 20 |
gridStyle, |
| 21 |
gridWidth, |
| 22 |
colWidth, |
| 23 |
debug = true, |
| 24 |
$next, |
| 25 |
$prev; |
| 26 |
|
| 27 |
// The bix X button that removes the entire row shortcode |
| 28 |
editor.addButton('gridable_row_remove', { |
| 29 |
tooltip: l10n.remove_row, |
| 30 |
icon: 'dashicon dashicons-no', |
| 31 |
onclick: function (event) { |
| 32 |
// first get the current selected node and search for his "row" parent |
| 33 |
var node = editor.selection.getNode(), |
| 34 |
wrap = editor.$(node).closest('.row.gridable-mceItem'); |
| 35 |
|
| 36 |
// now if there is a parent row, also remove the surrounding <p> tags |
| 37 |
if (wrap) { |
| 38 |
if (wrap.nextSibling) { |
| 39 |
editor.selection.select(wrap.nextSibling); |
| 40 |
} else if (wrap.previousSibling) { |
| 41 |
editor.selection.select(wrap.previousSibling); |
| 42 |
} else { |
| 43 |
editor.selection.select(wrap.parentNode); |
| 44 |
} |
| 45 |
|
| 46 |
editor.selection.collapse(true); |
| 47 |
editor.dom.remove(wrap); |
| 48 |
} else { |
| 49 |
editor.dom.remove(node); |
| 50 |
} |
| 51 |
} |
| 52 |
}); |
| 53 |
|
| 54 |
/** |
| 55 |
* The Add Column button comes with a few rules: |
| 56 |
* |
| 57 |
* * A row suppports only 6 columns |
| 58 |
* * When adding a new column take the space from the biggest one |
| 59 |
* |
| 60 |
*/ |
| 61 |
editor.addButton('gridable_add_col', { |
| 62 |
tooltip: l10n.add_column, |
| 63 |
icon: 'dashicon dashicons-plus', |
| 64 |
onclick: function (event) { |
| 65 |
var node = editor.selection.getNode(), |
| 66 |
wrap = editor.$(node).closest('.row.gridable-mceItem'), |
| 67 |
columns = wrap.find('.col.gridable-mceItem'), |
| 68 |
new_size = 0; |
| 69 |
|
| 70 |
if (columns.length > 0) { |
| 71 |
columns.each(function (i, el) { |
| 72 |
var current_size = editor.$(el).attr('data-sh-column-attr-size'); |
| 73 |
|
| 74 |
if ( current_size > 2 ) { |
| 75 |
editor.$(el).attr('data-sh-column-attr-size', current_size - 2); |
| 76 |
new_size += 2; |
| 77 |
return false; |
| 78 |
} |
| 79 |
}); |
| 80 |
} |
| 81 |
|
| 82 |
if ( new_size === 0 ) { |
| 83 |
new_size = 12; // asta e |
| 84 |
} |
| 85 |
|
| 86 |
/** |
| 87 |
* Create a new html template with the new column and append it to the current editing row |
| 88 |
*/ |
| 89 |
var tmp = getColTemplate({ |
| 90 |
atts: {size: new_size.toString()}, |
| 91 |
size: new_size.toString(), |
| 92 |
content: '<p>' + l10n.new_column_content + '</p>' |
| 93 |
}); |
| 94 |
|
| 95 |
node = editor.dom.create('DIV', {}, tmp); |
| 96 |
|
| 97 |
wrap[0].appendChild(node.children[0]); |
| 98 |
|
| 99 |
editor.execCommand('gridableAddResizeHandlers'); |
| 100 |
} |
| 101 |
}); |
| 102 |
|
| 103 |
editor.addButton('gridable_remove_col', { |
| 104 |
tooltip: l10n.remove_column, |
| 105 |
icon: 'dashicon dashicons-minus', |
| 106 |
onclick: function (event) { |
| 107 |
var node = editor.selection.getNode(), |
| 108 |
column = editor.$(node).closest('.col.gridable-mceItem'); |
| 109 |
|
| 110 |
// if (window.confirm('Are you sure you want to remove this column?')) { |
| 111 |
var column_size = editor.$(column).attr('data-sh-column-attr-size'); |
| 112 |
|
| 113 |
if (column[0].previousElementSibling !== null) { |
| 114 |
increase_column_size_with(column_size, column[0].previousElementSibling); |
| 115 |
} else if (column[0].nextElementSibling !== null) { |
| 116 |
increase_column_size_with(column_size, column[0].nextElementSibling); |
| 117 |
} else { |
| 118 |
editor.$(node).closest('.row.gridable-mceItem').remove(); |
| 119 |
} |
| 120 |
column.remove(); |
| 121 |
// } |
| 122 |
} |
| 123 |
}); |
| 124 |
|
| 125 |
editor.addButton('gridable_row_options', { |
| 126 |
tooltip: l10n.edit_row, |
| 127 |
icon: 'dashicon dashicons-edit', |
| 128 |
onclick: function (event) { |
| 129 |
|
| 130 |
var node = editor.selection.getNode(), |
| 131 |
row = editor.$(node).closest('.row.gridable-mceItem'); |
| 132 |
|
| 133 |
GridableOptionsModal.open('row', editor, row[0]); |
| 134 |
} |
| 135 |
}); |
| 136 |
|
| 137 |
editor.addButton('gridable_col_options', { |
| 138 |
tooltip: l10n.edit_column, |
| 139 |
icon: 'dashicon dashicons-edit', |
| 140 |
onclick: function (event) { |
| 141 |
|
| 142 |
var node = editor.selection.getNode(), |
| 143 |
column = editor.$(node).closest('.col.gridable-mceItem'); |
| 144 |
|
| 145 |
GridableOptionsModal.open('column', editor, column[0]); |
| 146 |
} |
| 147 |
}); |
| 148 |
|
| 149 |
editor.addButton('gridable_col_label', { |
| 150 |
text: l10n.column + ':', |
| 151 |
disabled: true, |
| 152 |
role: 'separator' |
| 153 |
}); |
| 154 |
|
| 155 |
editor.addButton('gridable_row_label', { |
| 156 |
text: l10n.row + ':', |
| 157 |
disabled: true, |
| 158 |
role: 'separator' |
| 159 |
}); |
| 160 |
|
| 161 |
|
| 162 |
// @TODO https://github.com/pixelgrade/gridable/issues/57 |
| 163 |
// editor.on('ExecCommand', function (args, e) { |
| 164 |
// if ( 'SelectAll' !== args.command ) { |
| 165 |
// return; |
| 166 |
// } |
| 167 |
// console.log( editor.selection.getRng() ); |
| 168 |
// }); |
| 169 |
// |
| 170 |
// editor.on('BeforeExecCommand', function (args) { |
| 171 |
// if ( 'SelectAll' !== args.command ) { |
| 172 |
// return; |
| 173 |
// } |
| 174 |
// console.log( args ); |
| 175 |
// console.log( editor.selection.getRng() ); |
| 176 |
// }); |
| 177 |
|
| 178 |
/** |
| 179 |
* Create the toolbar with the controls for row |
| 180 |
*/ |
| 181 |
editor.on('wptoolbar', function (args) { |
| 182 |
var selected_row = editor.dom.$(args.element).parents('.row.gridable-mceItem'); |
| 183 |
|
| 184 |
// if a row is focused we display the toolbar and add a CSS class |
| 185 |
if ( selected_row.length > 0 && ( ['P', 'h1', 'H2', 'H3', 'H4', 'H5', 'STRONG', 'SPAN', 'DIV', 'FONT', 'BR'].indexOf(args.element.tagName) !== -1 || args.element.className.indexOf('gridable-mceItem') !== -1 ) ) { |
| 186 |
// if ( selected_row.length > 0 ) { |
| 187 |
args.toolbar = toolbar; |
| 188 |
args.selection = selected_row[0]; |
| 189 |
selected_row.addClass('is-focused'); |
| 190 |
} else { // we need to ensure that the focused class is removed |
| 191 |
var $rows = editor.dom.$('.row.gridable-mceItem.is-focused'); |
| 192 |
if ($rows.length > 0) { |
| 193 |
$rows = $rows.removeClass('is-focused'); |
| 194 |
} |
| 195 |
} |
| 196 |
}); |
| 197 |
|
| 198 |
/** |
| 199 |
* Assign buttons for our toolbar |
| 200 |
* When the editor is initialized, we need to bind the resize events for every resize handler that may appear |
| 201 |
*/ |
| 202 |
editor.once('preinit', function () { |
| 203 |
if (editor.wp && editor.wp._createToolbar) { |
| 204 |
|
| 205 |
// the fist two options must be the add / remove columns |
| 206 |
var toolbar_buttons = [ |
| 207 |
'gridable_col_label', |
| 208 |
'gridable_add_col', |
| 209 |
'gridable_remove_col', |
| 210 |
]; |
| 211 |
|
| 212 |
if ( typeof gridable_column_options !== 'undefined' && Object.keys( gridable_column_options ).length > 1 ) { |
| 213 |
toolbar_buttons.push( 'gridable_col_options' ); |
| 214 |
} |
| 215 |
|
| 216 |
toolbar_buttons.push('|'); |
| 217 |
|
| 218 |
toolbar_buttons.push('gridable_row_label'); |
| 219 |
|
| 220 |
if ( typeof gridable_row_options !== 'undefined' && Object.keys( gridable_row_options ).length > 1 ) { |
| 221 |
// just a separator |
| 222 |
toolbar_buttons.push( 'gridable_row_options' ); |
| 223 |
} |
| 224 |
|
| 225 |
// the remove row button must be the last |
| 226 |
toolbar_buttons.push('gridable_row_remove'); |
| 227 |
|
| 228 |
toolbar = editor.wp._createToolbar( toolbar_buttons ); |
| 229 |
} |
| 230 |
}); |
| 231 |
|
| 232 |
/** |
| 233 |
* Whenever the cursor changes it's position the parent may be a grid column, then we need to add handlers |
| 234 |
*/ |
| 235 |
// editor.on('NodeChange', function (event) { |
| 236 |
// |
| 237 |
// if ('html' === window.getUserSetting('editor')) { |
| 238 |
// return; |
| 239 |
// } |
| 240 |
// |
| 241 |
// var el = editor.dom.$(event.element); |
| 242 |
// |
| 243 |
// }); |
| 244 |
|
| 245 |
editor.on('keydown', function (evt) { |
| 246 |
if ('html' === window.getUserSetting('editor')) { |
| 247 |
return; |
| 248 |
} |
| 249 |
|
| 250 |
/** |
| 251 |
* While pressing enter in editor the cursor should not be allowed the leave the column |
| 252 |
*/ |
| 253 |
if (evt.keyCode == 13) { // if Enter is pressed |
| 254 |
var dom = editor.dom, |
| 255 |
selection = editor.selection, |
| 256 |
settings = editor.settings, |
| 257 |
rng = selection.getRng(true), |
| 258 |
container = rng.startContainer, |
| 259 |
parentBlock = dom.getParent(container, dom.isBlock), // Find parent block and setup empty block paddings |
| 260 |
containerBlock = parentBlock ? dom.getParent(parentBlock.parentNode, dom.isBlock) : null; |
| 261 |
|
| 262 |
// Handle enter in column item |
| 263 |
if (typeof parentBlock !== "null" |
| 264 |
&& dom.isEmpty(parentBlock) |
| 265 |
&& containerBlock !== null |
| 266 |
&& typeof containerBlock.tagName !== "undefined" |
| 267 |
&& "DIV" === containerBlock.tagName |
| 268 |
&& containerBlock.className.indexOf("col gridable-mceItem") !== -1) { |
| 269 |
editor.execCommand("InsertLineBreak", false, evt); |
| 270 |
evt.preventDefault(); |
| 271 |
return false; |
| 272 |
} |
| 273 |
} |
| 274 |
}); |
| 275 |
|
| 276 |
/** |
| 277 |
* Event triggered when the content is set |
| 278 |
* Here we replace the shortcodes like [row] with <section class="row"> |
| 279 |
*/ |
| 280 |
editor.on('SetContent', function (event) { |
| 281 |
// console.group('GetContent'); |
| 282 |
if (!event.content || 'raw' === event.format || 'savecontent' === event.type || event.selection === true) { |
| 283 |
return; |
| 284 |
} |
| 285 |
|
| 286 |
editor.execCommand('gridableRender'); |
| 287 |
// console.groupEnd('GetContent'); |
| 288 |
}); |
| 289 |
|
| 290 |
/** |
| 291 |
* After we save the content ensure that the shortcodes are rendered back |
| 292 |
*/ |
| 293 |
editor.on('PreProcess', function (event) { |
| 294 |
if ('html' === window.getUserSetting('editor')) { |
| 295 |
return false; |
| 296 |
} else if ( editor.editorCommands.hasCustomCommand('gridableRestore' ) && event.save === true ) { |
| 297 |
editor.editorCommands.execCommand('gridableRestore'); |
| 298 |
} |
| 299 |
}); |
| 300 |
|
| 301 |
editor.on( 'pastePostProcess', function( event ) { |
| 302 |
var bm = tinyMCE.activeEditor.selection.getBookmark(); |
| 303 |
var node = event.target.selection.getNode(); |
| 304 |
|
| 305 |
// mceInsertContent is messing our resize handlers, we stick with this simple replce for now |
| 306 |
$(node).replaceWith( event.node.innerHTML ); |
| 307 |
// editor.execCommand('mceInsertContent', false, event.node.innerHTML); |
| 308 |
|
| 309 |
// event.target.selection.setNode( node ); |
| 310 |
// event.target.selection.collapse(0); |
| 311 |
tinyMCE.activeEditor.selection.moveToBookmark(bm); |
| 312 |
|
| 313 |
event.preventDefault(); |
| 314 |
}); |
| 315 |
|
| 316 |
/** |
| 317 |
* This function turns the grid shortcodes into HTML |
| 318 |
* |
| 319 |
* [row][/row] will turn into <section class="row"></section> |
| 320 |
* |
| 321 |
* @param content |
| 322 |
* @returns {*} |
| 323 |
*/ |
| 324 |
editor.addCommand('gridableRender', function () { |
| 325 |
|
| 326 |
var $save_btn = jQuery('#publishing-action .button'); |
| 327 |
$save_btn.attr('disabled', 'disabled'); |
| 328 |
|
| 329 |
// console.group('gridableRender'); |
| 330 |
var content = this.dom.doc.body.innerHTML; |
| 331 |
|
| 332 |
if (typeof content === "undefined") { |
| 333 |
return; |
| 334 |
} |
| 335 |
// first we need to strip grid shortcodes from p's |
| 336 |
content = remove_p_around_shortcodes(content); |
| 337 |
|
| 338 |
// same for cols |
| 339 |
content = maybe_replace_columns(content); |
| 340 |
|
| 341 |
// now replace row shortcodes with their HTML if there are any |
| 342 |
content = maybe_replace_rows(content); |
| 343 |
|
| 344 |
// event.content = content; |
| 345 |
this.dom.doc.body.innerHTML = content; |
| 346 |
|
| 347 |
// console.groupEnd('gridableRender'); |
| 348 |
// bind resize events |
| 349 |
editor.execCommand('gridableAddResizeHandlers'); |
| 350 |
|
| 351 |
$save_btn.removeAttr('disabled'); |
| 352 |
}); |
| 353 |
|
| 354 |
/** |
| 355 |
* This function must restore the shortcodes from the rendering state |
| 356 |
* |
| 357 |
* Since we are handling html we rather create a DOM element and use its innerHTML as parsing method |
| 358 |
* |
| 359 |
* <section class="row"></section> will turn into [row][/row] |
| 360 |
* |
| 361 |
* @param content |
| 362 |
* @returns {*|string} |
| 363 |
*/ |
| 364 |
editor.addCommand('gridableRestore', function () { |
| 365 |
|
| 366 |
var $save_btn = jQuery('#publishing-action .button'); |
| 367 |
$save_btn.attr('disabled', 'disabled'); |
| 368 |
|
| 369 |
// console.group('gridableRestore'); |
| 370 |
|
| 371 |
// hold all the content inside a HTML element.This way we keep it safe |
| 372 |
// var content_process = this.dom.create('DIV', {}, event.content); |
| 373 |
var content_process = this.dom.doc.body, |
| 374 |
restore_needed = false; |
| 375 |
|
| 376 |
content_process.innerHTML = content_process.innerHTML.replace(/(<p> <\/p>)/gi, '<br />'); |
| 377 |
|
| 378 |
// get all the columns inside the editor |
| 379 |
var columns = content_process.querySelectorAll('.col.gridable-mceItem'), |
| 380 |
columnReplacement = ''; |
| 381 |
|
| 382 |
for (var columnIndex = 0; columnIndex < columns.length; columnIndex++) { |
| 383 |
|
| 384 |
// create a new shortcode string like [col size="6"] |
| 385 |
var columnReplacement = wp.shortcode.string({ |
| 386 |
tag: 'col', |
| 387 |
// attrs: {size: columns[columnIndex].getAttribute('data-sh-column-attr-size')}, |
| 388 |
attrs: get_valid_column_attrs(columns[columnIndex]), |
| 389 |
content: columns[columnIndex].innerHTML.trim() |
| 390 |
}); |
| 391 |
|
| 392 |
// now replace the column html with the [col] shortcode |
| 393 |
content_process.innerHTML = content_process.innerHTML.replace(columns[columnIndex].outerHTML, columnReplacement); |
| 394 |
restore_needed = true; |
| 395 |
} |
| 396 |
|
| 397 |
// first restore back the row shortcodes |
| 398 |
var rows = content_process.querySelectorAll('.row.gridable-mceItem'), |
| 399 |
rowReplacement = ''; |
| 400 |
|
| 401 |
for (var rowIndex = 0; rowIndex < rows.length; rowIndex++) { |
| 402 |
// this is the shortcode representation of the row |
| 403 |
var rowReplacement = wp.shortcode.string({ |
| 404 |
tag: 'row', |
| 405 |
attrs: get_valid_row_attrs(rows[rowIndex]), |
| 406 |
content: rows[rowIndex].innerHTML.trim() |
| 407 |
}); |
| 408 |
|
| 409 |
// replace the row html with the shortcode |
| 410 |
content_process.innerHTML = content_process.innerHTML.replace(rows[rowIndex].outerHTML, rowReplacement); |
| 411 |
restore_needed = true; |
| 412 |
} |
| 413 |
|
| 414 |
if (restore_needed) { |
| 415 |
// @TODO find a better way to save the restored content without rendering it |
| 416 |
// this.setContent(content_process.innerHTML, { no_events: true}); |
| 417 |
content_process = this.dom.doc.body.innerHTML = content_process.innerHTML; |
| 418 |
// console.debug( content_process ); |
| 419 |
} |
| 420 |
// console.groupEnd('gridableRestore'); |
| 421 |
|
| 422 |
$save_btn.removeAttr('disabled'); |
| 423 |
}); |
| 424 |
|
| 425 |
editor.addCommand('gridableRemoveResize', function () { |
| 426 |
var $grids = editor.dom.$('.gridable__handle'); |
| 427 |
var $cols = editor.dom.$('.col.gridable-mceItem'); |
| 428 |
|
| 429 |
$cols.each( function (count, column) { |
| 430 |
var row = editor.dom.$(column).parents('.row.gridable-mceItem'); |
| 431 |
|
| 432 |
editor.dom.unbind( column, 'mousedown', onMouseDown ); |
| 433 |
editor.dom.unbind( row[0], 'mousemove', onMouseMove ); |
| 434 |
editor.dom.unbind( row[0], 'mouseup', onMouseUp ); |
| 435 |
editor.dom.unbind( row[0], 'mouseleave', onMouseUp ); |
| 436 |
}); |
| 437 |
|
| 438 |
$grids.remove(); |
| 439 |
}); |
| 440 |
|
| 441 |
/** |
| 442 |
* Function to add Column Resize Handlers and bound events |
| 443 |
*/ |
| 444 |
editor.addCommand('gridableAddResizeHandlers', function () { |
| 445 |
editor.execCommand('gridableRemoveResize'); |
| 446 |
|
| 447 |
var $cols = editor.dom.$('.col.gridable-mceItem'); |
| 448 |
|
| 449 |
$cols.each( function (count, column) { |
| 450 |
var row = editor.dom.$(column).parents('.row.gridable-mceItem'); |
| 451 |
|
| 452 |
editor.dom.bind( column, 'mousedown', onMouseDown ); |
| 453 |
editor.dom.bind( row[0], 'mousemove', onMouseMove, column ); |
| 454 |
editor.dom.bind( row[0], 'mouseup', onMouseUp, column ); |
| 455 |
editor.dom.bind( row[0], 'mouseleave', onMouseUp, column ); |
| 456 |
}); |
| 457 |
}); |
| 458 |
|
| 459 |
|
| 460 |
function getGridStyle(grid) { |
| 461 |
var gridStyle = getComputedStyle(grid), |
| 462 |
gridWidth = grid.clientWidth - parseFloat(gridStyle.paddingLeft) - parseFloat(gridStyle.paddingRight), |
| 463 |
colWidth = gridWidth / 12; |
| 464 |
|
| 465 |
return { |
| 466 |
gridStyle: gridStyle, |
| 467 |
gridWidth: gridWidth, |
| 468 |
colWidth: colWidth |
| 469 |
} |
| 470 |
} |
| 471 |
|
| 472 |
/** |
| 473 |
* Each column has a before pseudo element which acts as a resize handler |
| 474 |
* Detect if the click event is made over this pseude elements and add the resize class if so |
| 475 |
* @param e |
| 476 |
* @returns {boolean} |
| 477 |
*/ |
| 478 |
function onMouseDown(e) { |
| 479 |
// no class === no fun |
| 480 |
if ( typeof e.target.className === "undefined" ) { |
| 481 |
return true; |
| 482 |
} |
| 483 |
|
| 484 |
xStart = e.clientX; |
| 485 |
xLast = xStart; |
| 486 |
|
| 487 |
if ( e.target.className.indexOf('col gridable-mceItem') !== -1) { |
| 488 |
var $el = editor.dom.$( e.target ); |
| 489 |
|
| 490 |
if ( ( e.clientX - $el.offset().left ) <= 25 ) { |
| 491 |
e.preventDefault(); |
| 492 |
e.stopImmediatePropagation(); |
| 493 |
|
| 494 |
var grid = e.target.closest('.grid'), |
| 495 |
$grid = editor.$(grid); |
| 496 |
|
| 497 |
var gstyle = getGridStyle(grid); |
| 498 |
|
| 499 |
gridStyle = gstyle.gridStyle; |
| 500 |
gridWidth = gstyle.gridWidth; |
| 501 |
colWidth = gstyle.colWidth; |
| 502 |
|
| 503 |
$grid.addClass('grabbing'); |
| 504 |
|
| 505 |
$next = editor.dom.$(e.target); |
| 506 |
$prev = $next.prev('.col'); |
| 507 |
|
| 508 |
gridable_resizing = true; |
| 509 |
updateLoop(); |
| 510 |
|
| 511 |
var width = parseInt($next[0].offsetWidth, 10), |
| 512 |
colNo = Math.round(width / colWidth); |
| 513 |
} |
| 514 |
} |
| 515 |
} |
| 516 |
|
| 517 |
function onMouseMove(e) { |
| 518 |
if (gridable_resizing) { |
| 519 |
// console.log('handler mousemove'); |
| 520 |
e.preventDefault(); |
| 521 |
e.stopImmediatePropagation(); |
| 522 |
xLast = e.clientX; |
| 523 |
return false; |
| 524 |
} |
| 525 |
}; |
| 526 |
|
| 527 |
function onMouseUp(e) { |
| 528 |
// console.log('handler mouse out'); |
| 529 |
var grid = editor.dom.$(e.target).closest('.grid'), |
| 530 |
$grid = editor.dom.$(grid); |
| 531 |
|
| 532 |
$grid.removeClass('grabbing'); |
| 533 |
|
| 534 |
xEnd = e.clientX; |
| 535 |
gridable_resizing = false; |
| 536 |
}; |
| 537 |
|
| 538 |
function updateLoop() { |
| 539 |
|
| 540 |
if (!gridable_resizing || !xLast || !xStart) { |
| 541 |
return false; |
| 542 |
} |
| 543 |
|
| 544 |
if ( $next.length && $prev.length && typeof xStart !== "unedfined" ) { |
| 545 |
|
| 546 |
if ( xLast - xStart >= colWidth / 2 ) { |
| 547 |
var nextSpan = parseInt($next[0].getAttribute('data-sh-column-attr-size'), 10), |
| 548 |
prevSpan = parseInt($prev[0].getAttribute('data-sh-column-attr-size'), 10); |
| 549 |
|
| 550 |
if (nextSpan != 1) { |
| 551 |
$next[0].setAttribute('data-sh-column-attr-size', nextSpan - 1); |
| 552 |
$prev[0].setAttribute('data-sh-column-attr-size', prevSpan + 1); |
| 553 |
|
| 554 |
xStart += 1 * colWidth; |
| 555 |
} |
| 556 |
} else if (xStart - xLast >= colWidth / 2) { |
| 557 |
var nextSpan = parseInt($next[0].getAttribute('data-sh-column-attr-size'), 10), |
| 558 |
prevSpan = parseInt($prev[0].getAttribute('data-sh-column-attr-size'), 10); |
| 559 |
|
| 560 |
if (prevSpan != 1) { |
| 561 |
$next[0].setAttribute('data-sh-column-attr-size', nextSpan + 1); |
| 562 |
$prev[0].setAttribute('data-sh-column-attr-size', prevSpan - 1); |
| 563 |
|
| 564 |
xStart -= 1 * colWidth; |
| 565 |
} |
| 566 |
} |
| 567 |
} |
| 568 |
|
| 569 |
requestAnimationFrame(updateLoop); |
| 570 |
} |
| 571 |
|
| 572 |
|
| 573 |
/** === Helper functions ==== **/ |
| 574 |
|
| 575 |
/** |
| 576 |
* Try to keep our shortcodes clear of wraping P tags |
| 577 |
* This is very important since a [row] shortcode will turn into a <section class="row"> |
| 578 |
* In this case there is now way we can have a <p>[row]</p> turned into <p><section class="row"></p> |
| 579 |
* The world will end then. |
| 580 |
* |
| 581 |
* @param content |
| 582 |
* @returns {*} |
| 583 |
*/ |
| 584 |
var remove_p_around_shortcodes = function (content) { |
| 585 |
/** Starting shortcodes **/ |
| 586 |
|
| 587 |
// This catches anything like <p>[row] [col]</p> or <p>[row]</p> |
| 588 |
content = content.replace(/<p[^>]*>\s*(\[\s*row[^\]]*\])\s*(\[\s*col[^\]]*\])?\s*<\s*\/p\s*>/gmi, '$1$2'); |
| 589 |
|
| 590 |
// This catches anything like <p>[row] [col] some text </p> or <p>[row] some text</p> and replaces it with [row][col]<p>some text</p> or [row]<p>some text</p> |
| 591 |
content = content.replace(/<p[^>]*>\s*(\[\s*row[^\]]*\])\s*(\[\s*col[^\]]*\])?(.*?)<\s*\/p\s*>/gmi, '$1$2<p>$3</p>'); |
| 592 |
|
| 593 |
// This catches anything like <p>[col] some text </p> and replaces it with [col]<p> some text</p> |
| 594 |
content = content.replace(/<p[^>]*>\s*(\[\s*col[^\]]*\])(.*?)<\s*\/p\s*>/gmi, '$1<p>$2</p>'); |
| 595 |
|
| 596 |
/** Ending shortcodes or Ending and Opening **/ |
| 597 |
|
| 598 |
// This catches anything like <p>[/col] [/row]<p> or <p>[/col</p> or <p>[/row]</p> |
| 599 |
content = content.replace(/<p[^>]*>\s*(\[\s*\/col[^\]]*\])?\s*(\[\s*\/row[^\]]*\])?\s*<\s*\/p\s*>/gmi, '$1$2'); |
| 600 |
|
| 601 |
// This catches anything like <p>[/col] [col]<p> |
| 602 |
content = content.replace(/<p[^>]*>\s*(\[\s*\/col[^\]]*\])\s*(\[\s*col[^\]]*\])\s*<\s*\/p\s*>/gmi, '$1$2'); |
| 603 |
|
| 604 |
// This catches anything like <p>[/col] [col] some text<p> and replaces it with [/col][col]<p>some text</p> |
| 605 |
content = content.replace(/<p[^>]*>\s*(\[\s*\/col[^\]]*\])\s*(\[\s*col[^\]]*\])(.*?)<\s*\/p\s*>/gmi, '$1$2<p>$3</p>'); |
| 606 |
|
| 607 |
// This catches anything like <p>[/row] [row]<p> |
| 608 |
content = content.replace(/<p[^>]*>\s*(\[\s*\/row[^\]]*\])\s*(\[\s*row[^\]]*\])\s*<\s*\/p\s*>/gmi, '$1$2'); |
| 609 |
|
| 610 |
// This catches anything like <p>[/row] [row] some text<p> and replaces it with [/row] [row]<p>some text</p> |
| 611 |
content = content.replace(/<p[^>]*>\s*(\[\s*\/row[^\]]*\])\s*(\[\s*row[^\]]*\])(.*?)<\s*\/p\s*>/gmi, '$1$2'); |
| 612 |
|
| 613 |
// This is a fail safe in case there is a stranded </p> |
| 614 |
// This catches anything like [row]</p> or [row] [col]</p> |
| 615 |
content = content.replace(/(\[\s*row[^\]]*\])\s*(\[\s*col[^\]]*\])?\s*<\s*\/p\s*>/gmi, '$1$2'); |
| 616 |
// This catches anything like [col]</p> |
| 617 |
content = content.replace(/(\[\s*col[^\]]*\])\s*<\s*\/p\s*>/gmi, '$1'); |
| 618 |
|
| 619 |
// avoid casses like <p>[/col], you can never start a paragraf when you are just closing a column |
| 620 |
content = content.replace( /<p[^>]*>\s*(\[\s*\/col[^\]]*\])/gmi, '$1'); |
| 621 |
return content; |
| 622 |
}; |
| 623 |
|
| 624 |
/** |
| 625 |
* Incresease the column size based on a given number |
| 626 |
* @TODO maybe decrese the number of columns since we already know that 1 column will be deleted |
| 627 |
* @param column_size |
| 628 |
* @param node |
| 629 |
*/ |
| 630 |
function increase_column_size_with(column_size, node) { |
| 631 |
var current_size = editor.$(node).attr('data-sh-column-attr-size'); |
| 632 |
|
| 633 |
editor.$(node).attr('data-sh-column-attr-size', (parseInt(current_size) + parseInt(column_size))); |
| 634 |
} |
| 635 |
|
| 636 |
/** |
| 637 |
* Render [row] shortcodes |
| 638 |
* @param content |
| 639 |
* @returns {*} |
| 640 |
*/ |
| 641 |
function maybe_replace_rows(content) { |
| 642 |
var next = wp.shortcode.next('row', content); |
| 643 |
|
| 644 |
if (typeof next !== "undefined") { |
| 645 |
var template_attrs = { |
| 646 |
tag: "row", |
| 647 |
content: next.shortcode.content, |
| 648 |
atts: next.shortcode.attrs.named |
| 649 |
}; |
| 650 |
|
| 651 |
if ( typeof next.shortcode.attrs.named.bg_color !== "undefined" ) { |
| 652 |
template_attrs.atts.style = "background-color:" + next.shortcode.attrs.named.bg_color + ';'; |
| 653 |
} |
| 654 |
|
| 655 |
var row = getRowTemplate(template_attrs); |
| 656 |
|
| 657 |
var new_content = content.replace(next.content, row); |
| 658 |
|
| 659 |
// for recursivity, try again |
| 660 |
new_content = maybe_replace_rows(new_content); |
| 661 |
|
| 662 |
return new_content; |
| 663 |
} |
| 664 |
return content; |
| 665 |
} |
| 666 |
|
| 667 |
/** |
| 668 |
* Render columns shortcodes |
| 669 |
* @param content |
| 670 |
* @returns {*} |
| 671 |
*/ |
| 672 |
function maybe_replace_columns(content) { |
| 673 |
|
| 674 |
//content = remove_p_around_shortcodes(content); |
| 675 |
|
| 676 |
var next = wp.shortcode.next('col', content); |
| 677 |
|
| 678 |
if (typeof next !== "undefined") { |
| 679 |
|
| 680 |
var template_attrs = { |
| 681 |
tag: "col", |
| 682 |
content: next.shortcode.content, |
| 683 |
atts: next.shortcode.attrs.named |
| 684 |
}; |
| 685 |
|
| 686 |
if ( typeof next.shortcode.attrs.named.bg_color !== "undefined" ) { |
| 687 |
template_attrs.atts.style = "background-color:" + next.shortcode.attrs.named.bg_color + ';'; |
| 688 |
} |
| 689 |
|
| 690 |
// get the HTML template of a column |
| 691 |
var col = getColTemplate(template_attrs); |
| 692 |
|
| 693 |
var new_content = content.replace(next.content, col); |
| 694 |
|
| 695 |
// in case of inner columns, try again |
| 696 |
new_content = maybe_replace_columns(new_content); |
| 697 |
|
| 698 |
return new_content; |
| 699 |
} |
| 700 |
|
| 701 |
return content; |
| 702 |
} |
| 703 |
|
| 704 |
function get_valid_row_attrs(el) { |
| 705 |
var to_return = {}; |
| 706 |
|
| 707 |
var needle = 'data-sh-row-attr-'; |
| 708 |
|
| 709 |
Array.prototype.slice.call(el.attributes).forEach(function (item) { |
| 710 |
var attr_name = item.name.replace(needle, ''); |
| 711 |
|
| 712 |
if (item.name.indexOf(needle) !== -1 && attr_name in gridable_row_options) { |
| 713 |
|
| 714 |
if (item.value !== '') { |
| 715 |
to_return[attr_name] = item.value; |
| 716 |
} else if (typeof gridable_row_options[attr_name].default !== 'undefined') { |
| 717 |
to_return[attr_name] = gridable_row_options[attr_name].default; |
| 718 |
} |
| 719 |
} |
| 720 |
}); |
| 721 |
|
| 722 |
return to_return; |
| 723 |
} |
| 724 |
|
| 725 |
function get_valid_column_attrs(el) { |
| 726 |
|
| 727 |
var to_return = {}; |
| 728 |
var needle = 'data-sh-column-attr-'; |
| 729 |
|
| 730 |
Array.prototype.slice.call(el.attributes).forEach(function (item) { |
| 731 |
|
| 732 |
var attr_name = item.name.replace(needle, ''); |
| 733 |
|
| 734 |
if (item.name.indexOf(needle) !== -1 && attr_name in gridable_column_options) { |
| 735 |
|
| 736 |
if (item.value !== '') { |
| 737 |
to_return[attr_name] = item.value; |
| 738 |
} else if (typeof gridable_column_options[attr_name].default !== 'undefined') { |
| 739 |
to_return[attr_name] = gridable_column_options[attr_name].default; |
| 740 |
} |
| 741 |
} |
| 742 |
}); |
| 743 |
|
| 744 |
return to_return; |
| 745 |
} |
| 746 |
|
| 747 |
/** |
| 748 |
* Returns the html template of a [row] with `cols_nr` attribute |
| 749 |
* |
| 750 |
* @param args |
| 751 |
* @returns {*} |
| 752 |
*/ |
| 753 |
function getRowTemplate(args) { |
| 754 |
var rowSh = wp.template("gridable-grider-row"), |
| 755 |
atts = get_attrs_string('row', args.atts); |
| 756 |
return rowSh({ |
| 757 |
content: args.content, //wpAutoP(args.content), |
| 758 |
classes: 'row gridable-mceItem', |
| 759 |
atts: atts |
| 760 |
}); |
| 761 |
} |
| 762 |
|
| 763 |
/** |
| 764 |
* Returns the html template of a [col] with `size` attribute |
| 765 |
* |
| 766 |
* @param args |
| 767 |
* @returns {*} |
| 768 |
*/ |
| 769 |
function getColTemplate(args) { |
| 770 |
var atts = get_attrs_string('column', args.atts), |
| 771 |
colSh = wp.template("gridable-grider-col"); |
| 772 |
|
| 773 |
return colSh({ |
| 774 |
content: args.content, |
| 775 |
classes: 'col gridable-mceItem ', |
| 776 |
atts: atts |
| 777 |
}); |
| 778 |
} |
| 779 |
|
| 780 |
/** |
| 781 |
* First get all the attributes and save them from cols_nr="4" into `data-attr-sh-cols_nr="4"` |
| 782 |
* |
| 783 |
* @param tag |
| 784 |
* @param atts |
| 785 |
* @returns {string} |
| 786 |
*/ |
| 787 |
function get_attrs_string(tag, atts) { |
| 788 |
var atts_string = ''; |
| 789 |
|
| 790 |
if (typeof atts !== "undefined" && Object.keys(atts).length > 0) { |
| 791 |
Object.keys(atts).forEach(function (key, index) { |
| 792 |
if ( key === "style") { |
| 793 |
atts_string += key + '="' + atts[key] + '" '; |
| 794 |
} else { |
| 795 |
atts_string += ' data-sh-' + tag + '-attr-' + key + '="' + atts[key] + '" '; |
| 796 |
} |
| 797 |
}); |
| 798 |
} |
| 799 |
|
| 800 |
return atts_string; |
| 801 |
} |
| 802 |
|
| 803 |
/** |
| 804 |
* Avoid this |
| 805 |
* |
| 806 |
* @param content |
| 807 |
* @returns {*} |
| 808 |
*/ |
| 809 |
function wpAutoP(content) { |
| 810 |
if (switchEditors && switchEditors.wpautop) { |
| 811 |
content = switchEditors.wpautop(content); |
| 812 |
} |
| 813 |
return content; |
| 814 |
}; |
| 815 |
|
| 816 |
/** |
| 817 |
* Strip 'p' and 'br' tags, replace with line breaks. |
| 818 |
* |
| 819 |
* Reverses the effect of the WP editor autop functionality. |
| 820 |
* |
| 821 |
* @param {string} content Content with `<p>` and `<br>` tags inserted |
| 822 |
* @return {string} |
| 823 |
*/ |
| 824 |
function removeAutoP(content) { |
| 825 |
if (switchEditors && switchEditors.pre_wpautop) { |
| 826 |
content = switchEditors.pre_wpautop(content); |
| 827 |
} |
| 828 |
return content; |
| 829 |
}; |
| 830 |
|
| 831 |
/** Development functions, they can be removed in production **/ |
| 832 |
|
| 833 |
/** |
| 834 |
* For the moment just switch editors and they will take care |
| 835 |
*/ |
| 836 |
var clearfix = function () { |
| 837 |
switchEditors.go('content', 'html'); |
| 838 |
switchEditors.go('content', 'tmce'); |
| 839 |
}; |
| 840 |
|
| 841 |
/** |
| 842 |
* WordPress modal logic |
| 843 |
*/ |
| 844 |
var GridableOptionsModal = (function () { |
| 845 |
|
| 846 |
var postMediaFrame = wp.media.view.MediaFrame.Post; |
| 847 |
|
| 848 |
var MediaController = wp.media.controller.State.extend({ |
| 849 |
|
| 850 |
initialize: function (opts) { |
| 851 |
this.props = new Backbone.Model(opts.sh_atts); |
| 852 |
this.props.on('change:action', this.refresh, this); |
| 853 |
}, |
| 854 |
|
| 855 |
refresh: function () { |
| 856 |
if (this.frame && this.frame.toolbar) { |
| 857 |
this.frame.toolbar.get().refresh(); |
| 858 |
} |
| 859 |
}, |
| 860 |
|
| 861 |
insert: function () { |
| 862 |
|
| 863 |
if (typeof this.frame.options.$shortcode !== "undefined" && typeof this.props.changed !== {}) { |
| 864 |
|
| 865 |
var $sh = this.frame.options.$shortcode; |
| 866 |
var tag = this.frame.options.type; |
| 867 |
|
| 868 |
_.each(this.props.attributes, function (value, key) { |
| 869 |
$sh.setAttribute('data-sh-' + tag + '-attr-' + key, value); |
| 870 |
}); |
| 871 |
|
| 872 |
// apply style changes by re-rendering |
| 873 |
editor.execCommand('gridableRestore'); |
| 874 |
editor.execCommand('gridableRender'); |
| 875 |
|
| 876 |
this.frame.close(); |
| 877 |
} |
| 878 |
}, |
| 879 |
|
| 880 |
reset: function () { |
| 881 |
this.props.set('action', 'select'); |
| 882 |
this.props.set('currentShortcode', null); |
| 883 |
}, |
| 884 |
}); |
| 885 |
|
| 886 |
var Toolbar = wp.media.view.Toolbar.extend({ |
| 887 |
initialize: function () { |
| 888 |
_.defaults(this.options, { |
| 889 |
requires: false |
| 890 |
}); |
| 891 |
// Call 'initialize' directly on the parent class. |
| 892 |
wp.media.view.Toolbar.prototype.initialize.apply(this, arguments); |
| 893 |
}, |
| 894 |
|
| 895 |
refresh: function () { |
| 896 |
var action = this.controller.state().props.get('action'); |
| 897 |
if (this.get('insert')) { |
| 898 |
this.get('insert').model.set('disabled', action == 'select'); |
| 899 |
} |
| 900 |
/** |
| 901 |
* call 'refresh' directly on the parent class |
| 902 |
*/ |
| 903 |
wp.media.view.Toolbar.prototype.refresh.apply(this, arguments); |
| 904 |
} |
| 905 |
}); |
| 906 |
|
| 907 |
var editGridableAttributeField = wp.media.View.extend({ |
| 908 |
|
| 909 |
type: 'text', |
| 910 |
|
| 911 |
config: {}, |
| 912 |
|
| 913 |
tagName: 'div', |
| 914 |
|
| 915 |
className: 'gridable-attribute-field', |
| 916 |
|
| 917 |
events: { |
| 918 |
'input input': 'inputChanged', |
| 919 |
'input textarea': 'inputChanged', |
| 920 |
'change select': 'inputChanged', |
| 921 |
'change input[type="radio"]': 'inputChanged', |
| 922 |
'change input[type="checkbox"]': 'inputChanged', |
| 923 |
'change input[type="text"].select2': 'inputChanged' |
| 924 |
}, |
| 925 |
|
| 926 |
initialize: function () { |
| 927 |
this.config = this.options.config; |
| 928 |
this.type = this.options.config.type; |
| 929 |
}, |
| 930 |
|
| 931 |
render: function () { |
| 932 |
var tmpl_key = 'gridable-row-option-' + this.type, |
| 933 |
template = wp.template(tmpl_key); |
| 934 |
|
| 935 |
config = jQuery.extend({ |
| 936 |
id: 'gridable-ui-' + this.options.key, |
| 937 |
label: 'Text' |
| 938 |
}, this.config); |
| 939 |
|
| 940 |
var template_config = { |
| 941 |
key: this.options.key, |
| 942 |
label: this.config.label, |
| 943 |
value: this.config.default |
| 944 |
}; |
| 945 |
|
| 946 |
if (typeof this.options.model.attributes[this.options.key] !== "undefined") { |
| 947 |
template_config.value = this.options.model.attributes[this.options.key]; |
| 948 |
} |
| 949 |
|
| 950 |
if (this.type === 'checkbox') { |
| 951 |
template_config.checked = template_config.value === 'true' ? 'checked="checked"' : ''; |
| 952 |
} |
| 953 |
|
| 954 |
var element = template(template_config); |
| 955 |
|
| 956 |
this.$el.html(element); |
| 957 |
|
| 958 |
var self = this; |
| 959 |
|
| 960 |
// if there is a colorpicker left behind, init it now |
| 961 |
if ('color' === this.type) { |
| 962 |
this.$el.find('.colorpicker input:not(.wp-color-picker)').wpColorPicker({ |
| 963 |
hide: false, |
| 964 |
change: function (event, ui) { |
| 965 |
// event = standard jQuery event, produced by whichever control was changed. |
| 966 |
// ui = standard jQuery UI object, with a color member containing a Color.js object |
| 967 |
jQuery(this).parents('.media-frame-content').css('backgroundColor', ui.color.toString()); |
| 968 |
jQuery(this).val(ui.color.toString()); |
| 969 |
jQuery(this).trigger('input'); |
| 970 |
// change the bg color |
| 971 |
}, |
| 972 |
clear: function( event ) { |
| 973 |
// Clear button should make the field transparent |
| 974 |
self.options.model.attributes[self.options.key] = 'transparent'; |
| 975 |
} |
| 976 |
}); |
| 977 |
} |
| 978 |
|
| 979 |
if ('select' === self.type) { |
| 980 |
var options = []; |
| 981 |
|
| 982 |
_.each(self.config.options, function (label, value) { |
| 983 |
var opt_conf = {id: value, text: label}; |
| 984 |
if ( value === template_config.value ) { |
| 985 |
opt_conf.selected = true; |
| 986 |
} |
| 987 |
|
| 988 |
options.push(opt_conf); |
| 989 |
}); |
| 990 |
|
| 991 |
var $fieldSelect2 = self.$el.find('.selector select').select2({ |
| 992 |
placeholder: self.config.label || 'Search', |
| 993 |
data: options, |
| 994 |
// containerCssClass: 'gridable-select2', |
| 995 |
theme: 'gridable', |
| 996 |
minimumResultsForSearch: -1 |
| 997 |
}); |
| 998 |
} |
| 999 |
|
| 1000 |
return self; |
| 1001 |
}, |
| 1002 |
|
| 1003 |
/** |
| 1004 |
* Input Changed Update Callback. |
| 1005 |
* |
| 1006 |
* If the input field that has changed is for content or a valid attribute, |
| 1007 |
* then it should update the model. If a callback function is registered |
| 1008 |
* for this attribute, it should be called as well. |
| 1009 |
*/ |
| 1010 |
inputChanged: function (e) { |
| 1011 |
var $input = this.$el.find('.value_to_parse'); |
| 1012 |
if (this.type === 'checkbox') { |
| 1013 |
this.setValue($input.attr('name'), $input[0].checked ? 'true' : 'false'); |
| 1014 |
} else { |
| 1015 |
this.setValue($input.attr('name'), $input.val()); |
| 1016 |
} |
| 1017 |
}, |
| 1018 |
|
| 1019 |
getValue: function () { |
| 1020 |
return this.model.get('value'); |
| 1021 |
}, |
| 1022 |
|
| 1023 |
setValue: function (key, val) { |
| 1024 |
this.model.set(key, val); |
| 1025 |
}, |
| 1026 |
}); |
| 1027 |
|
| 1028 |
var Gridable_UI = wp.Backbone.View.extend({ |
| 1029 |
|
| 1030 |
initialize: function (options) { |
| 1031 |
this.controller = options.controller.state(); |
| 1032 |
//toolbar model looks for controller.state() |
| 1033 |
this.toolbar_controller = options.controller; |
| 1034 |
}, |
| 1035 |
|
| 1036 |
createToolbar: function (options) { |
| 1037 |
toolbarOptions = { |
| 1038 |
controller: this.toolbar_controller |
| 1039 |
}; |
| 1040 |
this.toolbar = new Toolbar(toolbarOptions); |
| 1041 |
this.views.add(this.toolbar); |
| 1042 |
}, |
| 1043 |
|
| 1044 |
render: function () { |
| 1045 |
|
| 1046 |
switch (this.controller.frame.options.type) { |
| 1047 |
case 'row' : |
| 1048 |
this.renderRowOptions(); |
| 1049 |
break; |
| 1050 |
case 'column' : |
| 1051 |
this.renderColumnOptions(); |
| 1052 |
break; |
| 1053 |
default: |
| 1054 |
console.log('render what?'); |
| 1055 |
break; |
| 1056 |
} |
| 1057 |
}, |
| 1058 |
|
| 1059 |
renderRowOptions: function () { |
| 1060 |
var atts = this.controller.frame.options.atts, |
| 1061 |
$modal = this.$el, |
| 1062 |
values = this.controller.props; |
| 1063 |
|
| 1064 |
if (typeof gridable_row_options !== "undefined") { |
| 1065 |
|
| 1066 |
_.each(gridable_row_options, function (config, key) { |
| 1067 |
|
| 1068 |
if ('cols_nr' === key || 'size' === key) { |
| 1069 |
return true; |
| 1070 |
} |
| 1071 |
|
| 1072 |
if (typeof config.type === 'undefined') { |
| 1073 |
config.type = 'text'; |
| 1074 |
} |
| 1075 |
|
| 1076 |
if (typeof config.default === 'undefined') { |
| 1077 |
config.default = 'Default'; |
| 1078 |
} |
| 1079 |
|
| 1080 |
// @TODO split this view object in multiple fields like select or ... etc |
| 1081 |
var view = new editGridableAttributeField({key: key, config: config, model: values}); |
| 1082 |
$modal.append(view.render().el); |
| 1083 |
}); |
| 1084 |
} |
| 1085 |
}, |
| 1086 |
|
| 1087 |
renderColumnOptions: function () { |
| 1088 |
var atts = this.controller.frame.options.atts, |
| 1089 |
$modal = this.$el, |
| 1090 |
values = this.controller.props; |
| 1091 |
|
| 1092 |
if (typeof gridable_column_options !== "undefined") { |
| 1093 |
|
| 1094 |
_.each(gridable_column_options, function (config, key) { |
| 1095 |
|
| 1096 |
if ('cols_nr' === key || 'size' === key) { |
| 1097 |
return true; |
| 1098 |
} |
| 1099 |
|
| 1100 |
if (typeof config.type === 'undefined') { |
| 1101 |
config.type = 'text'; |
| 1102 |
} |
| 1103 |
|
| 1104 |
if (typeof config.default === 'undefined') { |
| 1105 |
config.default = 'Default'; |
| 1106 |
} |
| 1107 |
|
| 1108 |
var view = new editGridableAttributeField({key: key, config: config, model: values}); |
| 1109 |
$modal.append(view.render().el); |
| 1110 |
}); |
| 1111 |
} |
| 1112 |
}, |
| 1113 |
|
| 1114 |
}); |
| 1115 |
|
| 1116 |
var mediaFrame = postMediaFrame.extend({ |
| 1117 |
|
| 1118 |
initialize: function () { |
| 1119 |
|
| 1120 |
postMediaFrame.prototype.initialize.apply(this, arguments); |
| 1121 |
|
| 1122 |
var id = 'gridable-ui', |
| 1123 |
title = 'Update ' + this.options.type + ' options', |
| 1124 |
sh_atts = {}, |
| 1125 |
needle = 'data-sh-column-attr-'; |
| 1126 |
|
| 1127 |
if (this.options.type === 'row') { |
| 1128 |
needle = 'data-sh-row-attr-'; |
| 1129 |
} |
| 1130 |
|
| 1131 |
Array.prototype.slice.call(this.options.$shortcode.attributes).forEach(function (item) { |
| 1132 |
if (item.name.indexOf(needle) !== -1) { |
| 1133 |
sh_atts[item.name.replace(needle, '')] = item.value; |
| 1134 |
} |
| 1135 |
}); |
| 1136 |
|
| 1137 |
var opts = { |
| 1138 |
id: id, |
| 1139 |
search: false, |
| 1140 |
router: false, |
| 1141 |
toolbar: id + '-toolbar', |
| 1142 |
menu: 'default', |
| 1143 |
title: title, |
| 1144 |
priority: 66, |
| 1145 |
content: id + '-content-update', |
| 1146 |
sh_atts: sh_atts |
| 1147 |
}; |
| 1148 |
|
| 1149 |
this.mediaController = new MediaController(opts); |
| 1150 |
this.states.add([this.mediaController]); |
| 1151 |
|
| 1152 |
this.on('content:render:' + id + '-content-update', _.bind(this.contentRender, this, 'gridable-ui', 'update')); |
| 1153 |
this.on('toolbar:create:gridable-ui-toolbar', this.toolbarCreate, this); |
| 1154 |
this.on('toolbar:render:gridable-ui-toolbar', this.toolbarRender, this); |
| 1155 |
this.on('menu:render:default', this.renderShortcodeUIMenu); |
| 1156 |
}, |
| 1157 |
|
| 1158 |
events: function () { |
| 1159 |
return _.extend({}, postMediaFrame.prototype.events, { |
| 1160 |
'click .media-menu-item': 'resetMediaController', |
| 1161 |
}); |
| 1162 |
}, |
| 1163 |
|
| 1164 |
resetMediaController: function (event) { |
| 1165 |
if (this.state() && 'undefined' !== typeof this.state().props && this.state().props.get('currentShortcode')) { |
| 1166 |
//this.mediaController.reset(); |
| 1167 |
this.contentRender('gridable-ui', 'update'); |
| 1168 |
} |
| 1169 |
}, |
| 1170 |
|
| 1171 |
contentRender: function (id, tab) { |
| 1172 |
|
| 1173 |
var view = new Gridable_UI({ |
| 1174 |
controller: this, |
| 1175 |
className: 'clearfix media-sidebar visible ' + id + '-content ' + id + '-content-' + tab |
| 1176 |
}); |
| 1177 |
|
| 1178 |
this.content.set(view); |
| 1179 |
}, |
| 1180 |
|
| 1181 |
toolbarRender: function (toolbar) { |
| 1182 |
}, |
| 1183 |
|
| 1184 |
toolbarCreate: function (toolbar) { |
| 1185 |
toolbar.view = new Toolbar({ |
| 1186 |
controller: this, |
| 1187 |
items: { |
| 1188 |
insert: { |
| 1189 |
text: 'Update ' + this.options.type, |
| 1190 |
style: 'primary', |
| 1191 |
priority: 80, |
| 1192 |
requires: false, |
| 1193 |
click: this.insertAction, |
| 1194 |
} |
| 1195 |
} |
| 1196 |
}); |
| 1197 |
}, |
| 1198 |
|
| 1199 |
renderShortcodeUIMenu: function (view) { |
| 1200 |
|
| 1201 |
// Hide menu if editing. |
| 1202 |
// @todo - fix this. |
| 1203 |
// This is a hack. |
| 1204 |
// I just can't work out how to do it properly... |
| 1205 |
// if ( view.controller.state().props && view.controller.state().props.get( 'currentShortcode' ) ) { |
| 1206 |
window.setTimeout(function () { |
| 1207 |
view.controller.$el.addClass('hide-menu'); |
| 1208 |
}); |
| 1209 |
// } |
| 1210 |
|
| 1211 |
}, |
| 1212 |
|
| 1213 |
insertAction: function () { |
| 1214 |
/* Trigger render_destroy */ |
| 1215 |
/* |
| 1216 |
* Action run before the shortcode overlay is destroyed. |
| 1217 |
* |
| 1218 |
* Called as `shortcode-ui.render_destroy`. |
| 1219 |
* |
| 1220 |
* @param shortcodeModel (object) |
| 1221 |
* Reference to the shortcode model used in this overlay. |
| 1222 |
*/ |
| 1223 |
// var hookName = 'shortcode-ui.render_destroy'; |
| 1224 |
// var shortcodeModel = this.controller.state().props.get( 'currentShortcode' ); |
| 1225 |
// wp.shortcake.hooks.doAction( hookName, shortcodeModel ); |
| 1226 |
|
| 1227 |
this.controller.state().insert(); |
| 1228 |
}, |
| 1229 |
}); |
| 1230 |
|
| 1231 |
function open(type, editor, shortcode) { |
| 1232 |
|
| 1233 |
wp.media.view.MediaFrame.Post = mediaFrame; |
| 1234 |
|
| 1235 |
var atts = get_shortcode_atts(type, shortcode); |
| 1236 |
|
| 1237 |
// @TODO process shortcode |
| 1238 |
var options = { |
| 1239 |
frame: 'post', |
| 1240 |
state: 'gridable-ui', |
| 1241 |
type: type, |
| 1242 |
atts: atts, |
| 1243 |
$shortcode: shortcode |
| 1244 |
}; |
| 1245 |
|
| 1246 |
wp.media.editor.remove(editor); |
| 1247 |
wp.media.editor.open(editor, options); |
| 1248 |
} |
| 1249 |
|
| 1250 |
function get_shortcode_atts(type, el) { |
| 1251 |
|
| 1252 |
var all_atts = el.attributes, |
| 1253 |
sh_atts = {}; |
| 1254 |
|
| 1255 |
var needle = 'data-sh-column-attr-'; |
| 1256 |
|
| 1257 |
if (type === 'row') { |
| 1258 |
needle = 'data-sh-row-attr-'; |
| 1259 |
} |
| 1260 |
|
| 1261 |
Array.prototype.slice.call(el.attributes).forEach(function (item) { |
| 1262 |
if (item.name.indexOf(needle) !== -1) { |
| 1263 |
sh_atts[item.name.replace(needle, '')] = item.value; |
| 1264 |
} |
| 1265 |
}); |
| 1266 |
|
| 1267 |
return sh_atts; |
| 1268 |
} |
| 1269 |
|
| 1270 |
return { |
| 1271 |
open: open |
| 1272 |
}; |
| 1273 |
})(); |
| 1274 |
}); |
| 1275 |
}); |
| 1276 |
})(jQuery, window); |