Best JavaScript code snippet using devicefarmer-stf
jquery.gridmanager.js
Source:jquery.gridmanager.js
1/*! gridmanager - v0.3.1 - 2014-07-272* http://neokoenig.github.io/jQuery-gridmanager/3* Copyright (c) 2014 Tom King; Licensed MIT */4(function($ ){5 /**6 * Main Gridmanager function7 * @method gridmanager8 * @returns gridmanager9 * @class gridmanager10 * @memberOf jQuery.fn11 */12 $.gridmanager = function(el, options){13 var gm = this;14 gm.$el = $(el);15 gm.el = el;16 gm.$el.data("gridmanager", gm);17 /**18 * API19 * @method appendHTMLSelectedCols20 * @param {string} html - HTML to append to selected columns21 * @returns null22 */23 gm.appendHTMLSelectedCols = function(html) {24 var canvas=gm.$el.find("#" + gm.options.canvasId);25 var cols = canvas.find(gm.options.colSelector);26 $.each(cols, function(){27 if($(this).hasClass(gm.options.gmEditClassSelected)) {28 $('.'+gm.options.gmEditRegion, this).append(html);29 }30 });31 };32 /**33 * INIT - Main initialising function to create the canvas, controls and initialise all click handlers34 * @method init35 * @returns null36 */37 gm.init = function(){38 gm.options = $.extend({},$.gridmanager.defaultOptions, options);39 gm.log("INIT");40 gm.addCSS(gm.options.cssInclude);41 gm.rteControl("init");42 gm.createCanvas();43 gm.createControls();44 gm.initControls();45 gm.initDefaultButtons();46 gm.initCanvas();47 gm.log("FINISHED");48 };49/*------------------------------------------ Canvas & Controls ---------------------------------------*/50 /**51 * Build and append the canvas, making sure existing HTML in the user's div is wrapped. Will also trigger Responsive classes to existing markup if specified52 * @method createCanvas53 * @returns null54 */55 gm.createCanvas = function(){56 gm.log("+ Create Canvas");57 var html=gm.$el.html();58 gm.$el.html("");59 $('<div/>', {'id': gm.options.canvasId, 'html':html }).appendTo(gm.$el);60 // Add responsive classes after initial loading of HTML, otherwise we lose the rows61 if(gm.options.addResponsiveClasses) {62 gm.addResponsiveness(gm.$el.find("#" + gm.options.canvasId));63 }64 // Add default editable regions: we try and do this early on, as then we don't need to replicate logic to add regions65 if(gm.options.autoEdit){66 gm.initMarkup(67 gm.$el.find("#" + gm.options.canvasId)68 .find("."+gm.options.colClass)69 .not("."+gm.options.rowClass)70 );71 }72 };73 /**74 * Looks for and wraps non gm commented markup75 * @method initMarkup76 * @returns null77 */78 gm.initMarkup = function(cols){79 var cTagOpen = '<!--'+gm.options.gmEditRegion+'-->',80 cTagClose = '<!--\/'+gm.options.gmEditRegion+'-->';81 // Loop over each column82 $.each(cols, function(i, col){83 var hasGmComment = false,84 hasNested = $(col).children().hasClass(gm.options.rowClass);85 // Search for comments within column contents86 // NB, at the moment this is just finding "any" comment for testing, but should search for <!--gm-*87 $.each($(col).contents(), function(x, node){88 if($(node)[0].nodeType === 8){89 hasGmComment = true;90 }91 });92 // Apply default commenting markup93 if(!hasGmComment){94 if(hasNested){95 // Apply nested wrap96 $.each($(col).contents(), function(i, val){97 if($(val).hasClass(gm.options.rowClass)){98 var prev=Array.prototype.reverse.call($(val).prevUntil("."+gm.options.rowClass)),99 after=$(val).nextUntil("."+gm.options.rowClass);100 if(!$(prev).hasClass(gm.options.gmEditRegion)){101 $(prev).first().before(cTagOpen).end()102 .last().after(cTagClose);103 }104 if(!$(after).hasClass(gm.options.gmEditRegion)){105 $(after).first().before(cTagOpen).end()106 .last().after(cTagClose);107 }108 }109 });110 }111 else {112 // Is there anything to wrap?113 if($(col).contents().length !== 0){114 // Apply default comment wrap115 $(col).html(cTagOpen+$(col).html()+cTagClose);116 }117 }118 }119 });120 gm.log("initMarkup ran");121 };122 /*123 Init global default buttons on cols, rows or both124 */125 gm.initDefaultButtons = function(){126 if(gm.options.colSelectEnabled) {127 gm.options.customControls.global_col.push({callback: gm.selectColClick, loc: 'top', iconClass: 'fa fa-square-o', title: 'Select Column'});128 }129 if(gm.options.editableRegionEnabled) {130 gm.options.customControls.global_col.push({callback: gm.addEditableAreaClick, loc: 'top', iconClass: 'fa fa-edit', title: 'Add Editable Region'});131 }132 };133 /**134 * Add missing reponsive classes to existing HTML135 * @method addResponsiveness136 * @param {} html137 * @returns CallExpression138 */139 gm.addResponsiveness = function(html) {140 if(html === '') { return; }141 var desktopRegex = gm.options.colDesktopClass+'(\\d+)',142 tabletRegex = gm.options.colTabletClass+'(\\d+)',143 phoneRegex = gm.options.colPhoneClass+'(\\d+)',144 desktopRegexObj = new RegExp(desktopRegex,'i'),145 tabletRegexObj = new RegExp(tabletRegex, 'i'),146 phoneRegexObj = new RegExp(phoneRegex, 'i');147 //new_html = '';148 return $(html).find(':regex(class,'+desktopRegex+'|'+tabletRegex+'|'+phoneRegex+')').each(function(i, el) {149 var elClasses = $(this).attr('class'), colNum = 2;150 var hasDesktop = desktopRegexObj.test(elClasses), hasPhone = phoneRegexObj.test(elClasses), hasTablet = tabletRegexObj.test(elClasses);151 colNum = (colNum = desktopRegexObj.exec(elClasses))? colNum[1] : ( (colNum = tabletRegexObj.exec(elClasses))? colNum[1] : phoneRegexObj.exec(elClasses)[1] );152 if(!hasDesktop) {153 $(this).addClass(gm.options.colDesktopClass+colNum);154 }155 if(!hasPhone) {156 $(this).addClass(gm.options.colPhoneClass+colNum);157 }158 if(!hasTablet) {159 $(this).addClass(gm.options.colTabletClass+colNum);160 }161 // Adds default column classes - probably shouldn't go here, but since we're doing an expensive search to add the responsive classes, it'll do for now.162 if(gm.options.addDefaultColumnClass){163 if(!$(this).hasClass(gm.options.colClass)){164 $(this).addClass(gm.options.colClass);165 }166 }167 });168 };169 /**170 * Build and prepend the control panel171 * @method createControls172 * @returns null173 */174 gm.createControls = function(){175 gm.log("+ Create Controls");176 var buttons=[];177 // Dynamically generated row template buttons178 $.each(gm.options.controlButtons, function(i, val){179 var _class=gm.generateButtonClass(val);180 buttons.push("<a title='Add Row " + _class + "' class='" + gm.options.controlButtonClass + " add" + _class + "'><span class='" + gm.options.controlButtonSpanClass + "'></span> " + _class + "</a>");181 gm.generateClickHandler(val);182 });183 /*184 Generate the control bar markup185 */186 gm.$el.prepend(187 $('<div/>',188 {'id': gm.options.controlId, 'class': gm.options.gmClearClass }189 ).prepend(190 $('<div/>', {"class": gm.options.rowClass}).html(191 $('<div/>', {"class": gm.options.colDesktopClass + gm.options.colMax}).addClass(gm.options.colAdditionalClass).html(192 $('<div/>', {'id': 'gm-addnew'})193 .addClass(gm.options.gmBtnGroup)194 .addClass(gm.options.gmFloatLeft).html(195 buttons.join("")196 )197 ).append(gm.options.controlAppend)198 )199 )200 );201 };202 /**203 * Adds a CSS file or CSS Framework required for specific customizations204 * @method addCSS205 * @param {} myStylesLocation206 * @returns string207 */208 gm.addCSS = function(myStylesLocation) {209 if(myStylesLocation !== '') {210 $('<link rel="stylesheet" href="'+myStylesLocation+'">').appendTo("head");211 }212 };213 /**214 * Clean all occurrences of a substring215 * @method cleanSubstring216 * @param {} regex217 * @param {} source218 * @param {} replacement219 * @returns CallExpression220 */221 gm.cleanSubstring = function(regex, source, replacement) {222 return source.replace(new RegExp(regex, 'g'), replacement);223 };224 /**225 * Switches the layout mode for Desktop, Tablets or Mobile Phones226 * @method switchLayoutMode227 * @param {} mode228 * @returns null229 */230 gm.switchLayoutMode = function(mode) {231 var canvas=gm.$el.find("#" + gm.options.canvasId), temp_html = canvas.html(), regex1 = '', regex2 = '', uimode = '';232 // Reset previous changes233 temp_html = gm.cleanSubstring(gm.options.classRenameSuffix, temp_html, '');234 uimode = $('div.gm-layout-mode > button > span');235 // Do replacements236 switch (mode) {237 case 768:238 regex1 = '(' + gm.options.colDesktopClass + '\\d+)';239 regex2 = '(' + gm.options.colPhoneClass + '\\d+)';240 gm.options.currentClassMode = gm.options.colTabletClass;241 gm.options.colSelector = gm.options.colTabletSelector;242 $(uimode).attr('class', 'fa fa-tablet').attr('title', 'Tablet');243 break;244 case 640:245 regex1 = '(' + gm.options.colDesktopClass + '\\d+)';246 regex2 = '(' + gm.options.colTabletClass + '\\d+)';247 gm.options.currentClassMode = gm.options.colPhoneClass;248 gm.options.colSelector = gm.options.colPhoneSelector;249 $(uimode).attr('class', 'fa fa-mobile-phone').attr('title', 'Phone');250 break;251 default:252 regex1 = '(' + gm.options.colPhoneClass + '\\d+)';253 regex2 = '(' + gm.options.colTabletClass + '\\d+)';254 gm.options.currentClassMode = gm.options.colDesktopClass;255 gm.options.colSelector = gm.options.colDesktopSelector;256 $(uimode).attr('class', 'fa fa-desktop').attr('title', 'Desktop');257 }258 gm.options.layoutDefaultMode = mode;259 temp_html = temp_html.replace(new RegExp((regex1+'(?=[^"]*">)'), 'gm'), '$1'+gm.options.classRenameSuffix);260 temp_html = temp_html.replace(new RegExp((regex2+'(?=[^"]*">)'), 'gm'), '$1'+gm.options.classRenameSuffix);261 canvas.html(temp_html);262 };263 /**264 * Add click functionality to the buttons265 * @method initControls266 * @returns null267 */268 gm.initControls = function(){269 var canvas=gm.$el.find("#" + gm.options.canvasId);270 gm.log("+ InitControls Running");271 // Turn editing on or off272 gm.$el.on("click", ".gm-preview", function(){273 if(gm.status){274 gm.deinitCanvas();275 $(this).parent().find(".gm-edit-mode").prop('disabled', true);276 } else {277 gm.initCanvas();278 $(this).parent().find(".gm-edit-mode").prop('disabled', false);279 }280 $(this).toggleClass(gm.options.gmDangerClass);281 // Switch Layout Mode282 }).on("click", ".gm-layout-mode a", function() {283 gm.switchLayoutMode($(this).data('width'));284 // Switch editing mode285 }).on("click", ".gm-edit-mode", function(){286 if(gm.mode === "visual"){287 gm.deinitCanvas();288 canvas.html($('<textarea/>').attr("cols", 130).attr("rows", 25).val(canvas.html()));289 gm.mode="html";290 $(this).parent().find(".gm-preview, .gm-layout-mode > button").prop('disabled', true);291 } else {292 var editedSource=canvas.find("textarea").val();293 canvas.html(editedSource);294 gm.initCanvas();295 gm.mode="visual";296 $(this).parent().find(".gm-preview, .gm-layout-mode > button").prop('disabled', false);297 }298 $(this).toggleClass(gm.options.gmDangerClass);299 // Make region editable300 }).on("click", "." + gm.options.gmEditRegion + ' .'+gm.options.gmContentRegion, function(){301 //gm.log("clicked editable");302 if(!$(this).attr("contenteditable")){303 $(this).attr("contenteditable", true);304 gm.rteControl("attach", $(this) );305 }306 // Save Function307 }).on("click", "a.gm-save", function(){308 gm.deinitCanvas();309 gm.saveremote();310 /* Row settings */311 }).on("click", "a.gm-rowSettings", function(){312 var row=$(this).closest(gm.options.rowSelector);313 var drawer=row.find(".gm-rowSettingsDrawer");314 if(drawer.length > 0){315 drawer.remove();316 } else {317 row.prepend(gm.generateRowSettings(row));318 }319 // Change Row ID via rowsettings320 }).on("blur", "input.gm-rowSettingsID", function(){321 var row=$(this).closest(gm.options.rowSelector);322 row.attr("id", $(this).val());323 // Remove a class from a row via rowsettings324 }).on("click", ".gm-toggleRowClass", function(){325 var row=$(this).closest(gm.options.rowSelector);326 var theClass=$(this).text().trim();327 row.toggleClass(theClass);328 if(row.hasClass(theClass)){329 $(this).addClass(gm.options.gmDangerClass);330 } else {331 $(this).removeClass(gm.options.gmDangerClass);332 }333 /* Col settings */334 }).on("click", "a.gm-colSettings", function(){335 var col=$(this).closest(gm.options.colSelector);336 var drawer=col.find(".gm-colSettingsDrawer");337 if(drawer.length > 0){338 drawer.remove();339 } else {340 col.prepend(gm.generateColSettings(col));341 }342 // Change Col ID via colsettings343 }).on("blur", "input.gm-colSettingsID", function(){344 var col=$(this).closest(gm.options.colSelector);345 col.attr("id", $(this).val());346 // Remove a class from a row via rowsettings347 }).on("click", ".gm-togglecolClass", function(){348 var col=$(this).closest(gm.options.colSelector);349 var theClass=$(this).text().trim();350 col.toggleClass(theClass);351 if(col.hasClass(theClass)){352 $(this).addClass(gm.options.gmDangerClass);353 } else {354 $(this).removeClass(gm.options.gmDangerClass);355 }356 // Add new column to existing row357 }).on("click", "a.gm-addColumn", function(){358 $(this).parent().after(gm.createCol(2));359 gm.switchLayoutMode(gm.options.layoutDefaultMode);360 gm.reset();361 // Add a nested row362 }).on("click", "a.gm-addRow", function(){363 gm.log("Adding nested row");364 $(this).closest("." +gm.options.gmEditClass).append(365 $("<div>").addClass(gm.options.rowClass)366 .html(gm.createCol(6))367 .append(gm.createCol(6)));368 gm.reset();369 // Decrease Column Size370 }).on("click", "a.gm-colDecrease", function(){371 var col = $(this).closest("." +gm.options.gmEditClass);372 var t=gm.getColClass(col);373 if(t.colWidth > parseInt(gm.options.colResizeStep, 10)){374 t.colWidth=(parseInt(t.colWidth, 10) - parseInt(gm.options.colResizeStep, 10));375 col.switchClass(t.colClass, gm.options.currentClassMode + t.colWidth, 200);376 }377 // Increase Column Size378 }).on("click", "a.gm-colIncrease", function(){379 var col = $(this).closest("." +gm.options.gmEditClass);380 var t=gm.getColClass(col);381 if(t.colWidth < gm.options.colMax){382 t.colWidth=(parseInt(t.colWidth, 10) + parseInt(gm.options.colResizeStep, 10));383 col.switchClass(t.colClass, gm.options.currentClassMode + t.colWidth, 200);384 }385 // Reset all teh things386 }).on("click", "a.gm-resetgrid", function(){387 canvas.html("");388 gm.reset();389 // Remove a col or row390 }).on("click", "a.gm-removeCol", function(){391 $(this).closest("." +gm.options.gmEditClass).animate({opacity: 'hide', width: 'hide', height: 'hide'}, 400, function(){this.remove();});392 gm.log("Column Removed");393 }).on("click", "a.gm-removeRow", function(){394 gm.log($(this).closest("." +gm.options.colSelector));395 $(this).closest("." +gm.options.gmEditClass).animate({opacity: 'hide', height: 'hide'}, 400, function(){396 this.remove();397 // Check for multiple editable regions and merge?398 });399 gm.log("Row Removed");400 // For all the above, prevent default.401 }).on("click", "a.gm-resetgrid, a.gm-remove, a.gm-removeRow, a.gm-save, button.gm-preview, a.gm-viewsource, a.gm-addColumn, a.gm-colDecrease, a.gm-colIncrease", function(e){402 gm.log("Clicked: " + $.grep((this).className.split(" "), function(v){403 return v.indexOf('gm-') === 0;404 }).join());405 e.preventDefault();406 });407 };408 /**409 * Add any custom buttons globally on all rows / cols410 * returns void411 * @method initGlobalCustomControls412 * @returns null413 */414 gm.initGlobalCustomControls=function(){415 var canvas=gm.$el.find("#" + gm.options.canvasId),416 elems=[],417 callback = null,418 btnClass = '';419 $.each(['row','col'], function(i, control_type) {420 if(typeof gm.options.customControls['global_'+control_type] !== 'undefined') {421 elems=canvas.find(gm.options[control_type+'Selector']);422 $.each(gm.options.customControls['global_'+control_type], function(i, curr_control) {423 // controls with no valid callbacks set are skipped424 if(typeof curr_control.callback === 'undefined') { return; }425 if(typeof curr_control.loc === 'undefined') {426 curr_control.loc = 'top';427 }428 if(typeof curr_control.iconClass === 'undefined') {429 curr_control.iconClass = 'fa fa-file-code-o';430 }431 if(typeof curr_control.btnLabel === 'undefined') {432 curr_control.btnLabel = '';433 }434 if(typeof curr_control.title === 'undefined') {435 curr_control.title = '';436 }437 btnClass = (typeof curr_control.callback === 'function')? (i+'_btn') : (curr_control.callback);438 btnObj = {439 element: 'a',440 btnClass: 'gm-'+btnClass,441 iconClass: curr_control.iconClass,442 btnLabel: curr_control.btnLabel,443 title: curr_control.title444 };445 $.each(elems, function(i, current_elem) {446 gm.setupCustomBtn(current_elem, curr_control.loc, 'window', curr_control.callback, btnObj);447 });448 });449 }450 });451 };452 /**453 * Add any custom buttons configured on the data attributes454 * returns void455 * @method initCustomControls456 * @returns null457 */458 gm.initCustomControls=function(){459 var canvas=gm.$el.find("#" + gm.options.canvasId),460 callbackParams = '',461 callbackScp = '',462 callbackFunc = '',463 btnLoc = '',464 btnObj = {},465 iconClass = '',466 btnLabel = '';467 $( ('.'+gm.options.colClass+':data,'+' .'+gm.options.rowClass+':data'), canvas).each(function(){468 for(prop in $(this).data()) {469 if(prop.indexOf('gmButton') === 0) {470 callbackFunc = prop.replace('gmButton','');471 callbackParams = $(this).data()[prop].split('|');472 // Cannot accept 0 params or empty callback function name473 if(callbackParams.length === 0 || callbackFunc === '') { break; }474 btnLoc = (typeof callbackParams[3] !== 'undefined')? callbackParams[3] : 'top';475 iconClass = (typeof callbackParams[2] !== 'undefined')? callbackParams[2] : 'fa fa-file-code-o';476 btnLabel = (typeof callbackParams[1] !== 'undefined')? callbackParams[1] : '';477 callbackScp = callbackParams[0];478 btnObj = {479 element: 'a',480 btnClass: ('gm-'+callbackFunc),481 iconClass: iconClass,482 btnLabel: btnLabel483 };484 gm.setupCustomBtn(this, btnLoc, callbackScp, callbackFunc, btnObj);485 break;486 }487 }488 });489 };490 /**491 * Configures custom button click callback function492 * returns bool, true on success false on failure493 * @container - container element that wraps the toolbar494 * @btnLoc - button location: "top" for the upper toolbar and "bottom" for the lower one495 * @callbackScp - function scope to use. "window" for global scope496 * @callbackFunc - function name to call when the user clicks the custom button497 * @btnObj - button object that contains properties for: tag name, title, icon class, button class and label498 * @method setupCustomBtn499 * @param {} container500 * @param {} btnLoc501 * @param {} callbackScp502 * @param {} callbackFunc503 * @param {} btnObj504 * @returns Literal505 */506 gm.setupCustomBtn=function(container, btnLoc, callbackScp, callbackFunc, btnObj) {507 var callback = null;508 // Ensure we have a valid callback, if not skip509 if(typeof callbackFunc === 'string') {510 callback = gm.isValidCallback(callbackScp, callbackFunc.toLowerCase());511 } else if(typeof callbackFunc === 'function') {512 callback = callbackFunc;513 } else {514 return false;515 }516 // Set default button location to the top toolbar517 btnLoc = (btnLoc === 'bottom')? ':last' : ':first';518 // Add the button to the selected toolbar519 $( ('.'+gm.options.gmToolClass+btnLoc), container).append(gm.buttonFactory([btnObj])).find(':last').on('click', function(e) {520 callback(container, this);521 e.preventDefault();522 });523 return true;524 };525 /*526 Clears any comments inside a given element527 @elem - element to clear html comments on528 returns void529 */530 gm.clearComments = function(elem) {531 $(elem, '#'+gm.options.canvasId).contents().filter(function() {532 return this.nodeType === 8;533 }).remove();534 };535 /**536 * Checks that a callback exists and returns it if available537 * returns function538 * @callbackScp - function scope to use. "window" for global scope539 * @callbackFunc - function name to call when the user clicks the custom button540 * @method isValidCallback541 * @param {} callbackScp542 * @param {} callbackFunc543 * @returns callback544 */545 gm.isValidCallback=function(callbackScp, callbackFunc){546 var callback = null;547 if(callbackScp === 'window') {548 if(typeof window[callbackFunc] === 'function') {549 callback = window[callbackFunc];550 } else { // If the global function is not valid there is nothing to do551 return false;552 }553 } else if(typeof window[callbackScp][callbackFunc] === 'function') {554 callback = window[callbackScp][callbackFunc];555 } else { // If there is no valid callback there is nothing to do556 return false;557 }558 return callback;559 };560 /**561 * Get the col-md-6 class, returning 6 as well from column562 * returns colDesktopClass: the full col-md-6 class563 * colWidth: just the last integer of classname564 * @col - column to look at565 * @method getColClass566 * @param {} col567 * @return ObjectExpression568 */569 gm.getColClass=function(col){570 var colClass=$.grep(col.attr("class").split(" "), function(v){571 return v.indexOf(gm.options.currentClassMode) === 0;572 }).join();573 var colWidth=colClass.replace(gm.options.currentClassMode, "");574 return {colClass:colClass, colWidth:colWidth};575 };576 /*577 Run (if set) any custom init/deinit filters on the gridmanager canvas578 @canvasElem - canvas wrapper container with the entire layout html579 @isInit - flag that indicates if the method is running during init or deinit.580 true - if its running during the init process, or false - during the deinit (cleanup) process581 returns void582 */583 gm.runFilter=function(canvasElem, isInit){584 if(typeof gm.options.filterCallback === 'function') {585 gm.options.filterCallback(canvasElem, isInit);586 }587 if(gm.options.editableRegionEnabled) {588 gm.editableAreaFilter(canvasElem, isInit);589 }590 };591 /**592 * Turns canvas into gm-editing mode - does most of the hard work here593 * @method initCanvas594 * @returns null595 */596 gm.initCanvas = function(){597 // cache canvas598 var canvas=gm.$el.find("#" + gm.options.canvasId);599 gm.switchLayoutMode(gm.options.layoutDefaultMode);600 var cols=canvas.find(gm.options.colSelector);601 var rows=canvas.find(gm.options.rowSelector);602 gm.log("+ InitCanvas Running");603 // Show the template controls604 gm.$el.find("#gm-addnew").show();605 // Sort Rows First606 gm.activateRows(rows);607 // Now Columns608 gm.activateCols(cols);609 // Run custom init callback filter610 gm.runFilter(canvas, true);611 // Get cols & rows again after filter execution612 cols=canvas.find(gm.options.colSelector);613 rows=canvas.find(gm.options.rowSelector);614 // Make Rows sortable615 canvas.sortable({616 items: rows,617 axis: 'y',618 placeholder: gm.options.rowSortingClass,619 handle: ".gm-moveRow",620 forcePlaceholderSize: true, opacity: 0.7, revert: true,621 tolerance: "pointer",622 cursor: "move"623 });624 /*625 Make columns sortable626 This needs to be applied to each element, otherwise containment leaks627 */628 $.each(rows, function(i, val){629 $(val).sortable({630 items: $(val).find(gm.options.colSelector),631 axis: 'x',632 handle: ".gm-moveCol",633 forcePlaceholderSize: true, opacity: 0.7, revert: true,634 tolerance: "pointer",635 containment: $(val),636 cursor: "move"637 });638 });639 /* Make rows sortable640 cols.sortable({641 items: gm.options.rowSelector,642 axis: 'y',643 handle: ".gm-moveRow",644 forcePlaceholderSize: true, opacity: 0.7, revert: true,645 tolerance: "pointer",646 cursor: "move"647 }); */648 gm.status=true;649 gm.mode="visual";650 gm.initCustomControls();651 gm.initGlobalCustomControls();652 gm.initNewContentElem();653 };654 /**655 * Removes canvas editing mode656 * @method deinitCanvas657 * @returns null658 */659 gm.deinitCanvas = function(){660 // cache canvas661 var canvas=gm.$el.find("#" + gm.options.canvasId);662 var cols=canvas.find(gm.options.colSelector);663 var rows=canvas.find(gm.options.rowSelector);664 gm.log("- deInitCanvas Running");665 // Hide template control666 gm.$el.find("#gm-addnew").hide();667 // Sort Rows First668 gm.deactivateRows(rows);669 // Now Columns670 gm.deactivateCols(cols);671 // Clean markup672 gm.cleanup();673 gm.runFilter(canvas, false);674 gm.status=false;675 };676 /**677 * Push cleaned div content somewhere to save it678 * @method saveremote679 * @returns null680 */681 gm.saveremote = function(){682 var canvas=gm.$el.find("#" + gm.options.canvasId);683 $.ajax({684 type: "POST",685 url: gm.options.remoteURL,686 data: {content: canvas.html()}687 });688 gm.log("Save Function Called");689 };690/*------------------------------------------ ROWS ---------------------------------------*/691 /**692 * Look for pre-existing rows and add editing tools as appropriate693 * @rows: elements to act on694 * @method activateRows695 * @param {object} rows - rows to act on696 * @returns null697 */698 gm.activateRows = function(rows){699 gm.log("++ Activate Rows");700 rows.addClass(gm.options.gmEditClass)701 .prepend(gm.toolFactory(gm.options.rowButtonsPrepend))702 .append(gm.toolFactory(gm.options.rowButtonsAppend));703 };704 /**705 * Look for pre-existing rows and remove editing classes as appropriate706 * @rows: elements to act on707 * @method deactivateRows708 * @param {object} rows - rows to act on709 * @returns null710 */711 gm.deactivateRows = function(rows){712 gm.log("-- DeActivate Rows");713 rows.removeClass(gm.options.gmEditClass)714 .removeClass("ui-sortable")715 .removeAttr("style");716 };717 /**718 * Create a single row with appropriate editing tools & nested columns719 * @method createRow720 * @param {array} colWidths - array of css class integers, i.e [2,4,5]721 * @returns row722 */723 gm.createRow = function(colWidths){724 var row= $("<div/>", {"class": gm.options.rowClass + " " + gm.options.gmEditClass});725 $.each(colWidths, function(i, val){726 row.append(gm.createCol(val));727 });728 gm.log("++ Created Row");729 return row;730 };731 /**732 * Create the row specific settings box733 * @method generateRowSettings734 * @param {object} row - row to act on735 * @return MemberExpression736 */737 gm.generateRowSettings = function(row){738 // Row class toggle buttons739 var classBtns=[];740 $.each(gm.options.rowCustomClasses, function(i, val){741 var btn=$("<button/>")742 .addClass("gm-toggleRowClass")743 .addClass(gm.options.controlButtonClass)744 .append(745 $("<span/>")746 .addClass(gm.options.controlButtonSpanClass)747 ).append(" " + val);748 if(row.hasClass(val)){749 btn.addClass(gm.options.gmDangerClass);750 }751 classBtns.push(btn[0].outerHTML);752 });753 // Row settings drawer754 var html=$("<div/>")755 .addClass("gm-rowSettingsDrawer")756 .addClass(gm.options.gmToolClass)757 .addClass(gm.options.gmClearClass)758 .prepend($("<div />")759 .addClass(gm.options.gmBtnGroup)760 .addClass(gm.options.gmFloatLeft)761 .html(classBtns.join("")))762 .append($("<div />").addClass("pull-right").html(763 $("<label />").html("Row ID ").append(764 $("<input>").addClass("gm-rowSettingsID").attr({type: 'text', placeholder: 'Row ID', value: row.attr("id")})765 )766 ));767 return html[0].outerHTML;768 };769 /**770 * Create the col specific settings box771 * @method generateColSettings772 * @param {object} col - Column to act on773 * @return MemberExpression774 */775 gm.generateColSettings = function(col){776 // Col class toggle buttons777 var classBtns=[];778 $.each(gm.options.colCustomClasses, function(i, val){779 var btn=$("<button/>")780 .addClass("gm-togglecolClass")781 .addClass(gm.options.controlButtonClass)782 .append(783 $("<span/>")784 .addClass(gm.options.controlButtonSpanClass)785 ).append(" " + val);786 if(col.hasClass(val)){787 btn.addClass(gm.options.gmDangerClass);788 }789 classBtns.push(btn[0].outerHTML);790 });791 // col settings drawer792 var html=$("<div/>")793 .addClass("gm-colSettingsDrawer")794 .addClass(gm.options.gmToolClass)795 .addClass(gm.options.gmClearClass)796 .prepend($("<div />")797 .addClass(gm.options.gmBtnGroup)798 .addClass(gm.options.gmFloatLeft)799 .html(classBtns.join("")))800 .append($("<div />").addClass("pull-right").html(801 $("<label />").html("col ID ").append(802 $("<input>")803 .addClass("gm-colSettingsID")804 .attr({type: 'text', placeholder: 'col ID', value: col.attr("id")})805 )806 ));807 return html[0].outerHTML;808 };809/*------------------------------------------ COLS ---------------------------------------*/810 /**811 * Look for pre-existing columns and add editing tools as appropriate812 * @method activateCols813 * @param {object} cols - elements to act on814 * @returns null815 */816 gm.activateCols = function(cols){817 cols.addClass(gm.options.gmEditClass);818 // For each column,819 $.each(cols, function(i, column){820 $(column).prepend(gm.toolFactory(gm.options.colButtonsPrepend));821 $(column).append(gm.toolFactory(gm.options.colButtonsAppend));822 });823 gm.log("++ Activate Cols Ran");824 };825 /**826 * Look for pre-existing columns and removeediting tools as appropriate827 * @method deactivateCols828 * @param {object} cols - elements to act on829 * @returns null830 */831 gm.deactivateCols = function(cols){832 cols.removeClass(gm.options.gmEditClass)833 .removeClass(gm.options.gmEditClassSelected)834 .removeClass("ui-sortable");835 $.each(cols.children(), function(i, val){836 // Grab contents of editable regions and unwrap837 if($(val).hasClass(gm.options.gmEditRegion)){838 if($(val).html() !== ''){839 $(val).contents().unwrap();840 } else {841 // Deals with empty editable regions842 $(val).remove();843 }844 }845 });846 gm.log("-- deActivate Cols Ran");847 };848 /**849 * Create a single column with appropriate editing tools850 * @method createCol851 * @param {integer} size - width of the column to create, i.e 6852 * @returns null853 */854 gm.createCol = function(size){855 var col= $("<div/>")856 .addClass(gm.options.colClass)857 .addClass(gm.options.colDesktopClass + size)858 .addClass(gm.options.colTabletClass + size)859 .addClass(gm.options.colPhoneClass + size)860 .addClass(gm.options.gmEditClass)861 .addClass(gm.options.colAdditionalClass)862 .html(gm.toolFactory(gm.options.colButtonsPrepend))863 .prepend(gm.toolFactory(gm.options.colButtonsPrepend))864 .append(gm.toolFactory(gm.options.colButtonsAppend));865 gm.log("++ Created Column " + size);866 return col;867 };868/*------------------------------------------ Editable Regions ---------------------------------------*/869 /*870 Callback called when a the new editable area button is clicked871 @container - container element that wraps the select button872 @btn - button element that was clicked873 returns void874 */875 gm.addEditableAreaClick = function(container, btn) {876 var cTagOpen = '<!--'+gm.options.gmEditRegion+'-->',877 cTagClose = '<!--\/'+gm.options.gmEditRegion+'-->',878 elem = null;879 $(('.'+gm.options.gmToolClass+':last'),container)880 .before(elem = $('<div>').addClass(gm.options.gmEditRegion+' '+gm.options.contentDraggableClass)881 .append(gm.options.controlContentElem+'<div class="'+gm.options.gmContentRegion+'"><p>New Content</p></div>')).before(cTagClose).prev().before(cTagOpen);882 gm.initNewContentElem(elem);883 };884 /*885 Prepares any new content element inside columns so inner toolbars buttons work886 and any drag & drop functionality.887 @newElem - Container of the new content element added into a col888 returns void889 */890 gm.initNewContentElem = function(newElem) {891 var parentCols = null;892 if(typeof newElem === 'undefined') {893 parentCols = gm.$el.find('.'+gm.options.colClass);894 } else {895 parentCols = newElem.closest('.'+gm.options.colClass);896 }897 $.each(parentCols, function(i, col) {898 $(col).on('click', '.gm-delete', function(e) {899 $(this).closest('.'+gm.options.gmEditRegion).remove();900 gm.resetCommentTags(col);901 e.preventDefault();902 });903 $(col).sortable({904 items: '.'+gm.options.contentDraggableClass,905 axis: 'y',906 placeholder: gm.options.rowSortingClass,907 handle: "."+gm.options.controlMove,908 forcePlaceholderSize: true, opacity: 0.7, revert: true,909 tolerance: "pointer",910 cursor: "move",911 stop: function(e, ui) {912 gm.resetCommentTags($(ui.item).parent());913 }914 });915 });916 };917 /*918 Resets the comment tags for editable elements919 @elem - Element to reset the editable comments on920 returns void921 */922 gm.resetCommentTags = function(elem) {923 var cTagOpen = '<!--'+gm.options.gmEditRegion+'-->',924 cTagClose = '<!--\/'+gm.options.gmEditRegion+'-->';925 // First remove all existing comments926 gm.clearComments(elem);927 // Now replace these comment tags928 $('.'+gm.options.gmEditRegion, elem).before(cTagOpen).after(cTagClose);929 };930 /*931 Callback called when a the column selection button is clicked932 @container - container element that wraps the select button933 @btn - button element that was clicked934 returns void935 */936 gm.selectColClick = function(container, btn) {937 $(btn).toggleClass('fa fa-square-o fa fa-check-square-o');938 if($(btn).hasClass('fa-check-square-o')) {939 $(container).addClass(gm.options.gmEditClassSelected);940 } else {941 $(container).removeClass(gm.options.gmEditClassSelected);942 }943 };944 /*945 Filter method to restore editable regions in edit mode.946 */947 gm.editableAreaFilter = function(canvasElem, isInit) {948 if(isInit) {949 var cTagOpen = '<!--'+gm.options.gmEditRegion+'-->',950 cTagClose = '<!--\/'+gm.options.gmEditRegion+'-->',951 regex = new RegExp('(?:'+cTagOpen+')\\s*([\\s\\S]+?)\\s*(?:'+cTagClose+')', 'g'),952 html = $(canvasElem).html(),953 rep = cTagOpen+'<div class="'+gm.options.gmEditRegion+' '+gm.options.contentDraggableClass+'">'+gm.options.controlContentElem +'<div class="'+gm.options.gmContentRegion+'">$1</div></div>'+cTagClose;954 html = html.replace(regex, rep);955 $(canvasElem).html(html);956 gm.log("editableAreaFilter init ran");957 } else {958 $('.'+gm.options.controlNestedEditable, canvasElem).remove();959 $('.'+gm.options.gmContentRegion).contents().unwrap();960 gm.log("editableAreaFilter deinit ran");961 }962 };963/*------------------------------------------ BTNs ---------------------------------------*/964 /**965 * Returns an editing div with appropriate btns as passed in966 * @method toolFactory967 * @param {array} btns - Array of buttons (see options)968 * @return MemberExpression969 */970 gm.toolFactory=function(btns){971 var tools=$("<div/>")972 .addClass(gm.options.gmToolClass)973 .addClass(gm.options.gmClearClass)974 .html(gm.buttonFactory(btns));975 return tools[0].outerHTML;976 };977 /**978 * Returns html string of buttons979 * @method buttonFactory980 * @param {array} btns - Array of button configurations (see options)981 * @return CallExpression982 */983 gm.buttonFactory=function(btns){984 var buttons=[];985 $.each(btns, function(i, val){986 val.btnLabel = (typeof val.btnLabel === 'undefined')? '' : val.btnLabel;987 val.title = (typeof val.title === 'undefined')? '' : val.title;988 buttons.push("<" + val.element +" title='" + val.title + "' class='" + val.btnClass + "'><span class='"+val.iconClass+"'></span> " + val.btnLabel + "</" + val.element + "> ");989 });990 return buttons.join("");991 };992 /**993 * Basically just turns [2,4,6] into 2-4-6994 * @method generateButtonClass995 * @param {array} arr - An array of widths996 * @return string997 */998 gm.generateButtonClass=function(arr){999 var string="";1000 $.each(arr, function( i , val ) {1001 string=string + "-" + val;1002 });1003 return string;1004 };1005 /**1006 * click handlers for dynamic row template buttons1007 * @method generateClickHandler1008 * @param {array} colWidths - array of column widths, i.e [2,3,2]1009 * @returns null1010 */1011 gm.generateClickHandler= function(colWidths){1012 var string="a.add" + gm.generateButtonClass(colWidths);1013 var canvas=gm.$el.find("#" + gm.options.canvasId);1014 gm.$el.on("click", string, function(e){1015 gm.log("Clicked " + string);1016 canvas.prepend(gm.createRow(colWidths));1017 gm.reset();1018 e.preventDefault();1019 });1020 };1021/*------------------------------------------ RTEs ---------------------------------------*/1022 /**1023 * Starts, stops, looks for and attaches RTEs1024 * @method rteControl1025 * @param {string} action - options are init, attach, stop1026 * @param {object} element - object to attach an RTE to1027 * @returns null1028 */1029 gm.rteControl=function(action, element){1030 gm.log("RTE " + gm.options.rte + ' ' +action);1031 switch (action) {1032 case 'init':1033 if(typeof window.CKEDITOR !== 'undefined'){1034 gm.options.rte='ckeditor';1035 gm.log("++ CKEDITOR Found");1036 window.CKEDITOR.disableAutoInline = true;1037 }1038 if(typeof window.tinymce !== 'undefined'){1039 gm.options.rte='tinymce';1040 gm.log("++ TINYMCE Found");1041 }1042 break;1043 case 'attach':1044 switch (gm.options.rte) {1045 case 'tinymce':1046 if(!(element).hasClass("mce-content-body")){1047 element.tinymce(gm.options.tinymce.config);1048 }1049 break;1050 case 'ckeditor':1051 $(element).ckeditor(gm.options.ckeditor);1052 break;1053 default:1054 gm.log("No RTE specified for attach");1055 }1056 break; //end Attach1057 case 'stop':1058 switch (gm.options.rte) {1059 case 'tinymce':1060 // destroy TinyMCE1061 window.tinymce.remove();1062 gm.log("-- TinyMCE destroyed");1063 break;1064 case 'ckeditor':1065 // destroy ckeditor1066 for(var name in window.CKEDITOR.instances)1067 {1068 window.CKEDITOR.instances[name].destroy();1069 }1070 gm.log("-- CKEDITOR destroyed");1071 break;1072 default:1073 gm.log("No RTE specified for stop");1074 }1075 break; //end stop1076 default:1077 gm.log("No RTE Action specified");1078 }1079 };1080/*------------------------------------------ Useful functions ---------------------------------------*/1081 /**1082 * Quick reset - deinit & init the canvas1083 * @method reset1084 * @returns null1085 */1086 gm.reset=function(){1087 gm.log("~~RESET~~");1088 gm.deinitCanvas();1089 gm.initCanvas();1090 };1091 /**1092 * Remove all extraneous markup1093 * @method cleanup1094 * @returns null1095 */1096 gm.cleanup = function(){1097 var canvas,1098 content;1099 // cache canvas1100 canvas = gm.$el.find("#" + gm.options.canvasId);1101 /**1102 * Determine the current edit mode and get the content based upon the resultant1103 * context to prevent content in source mode from being lost on save, as such:1104 *1105 * edit mode (source): canvas.find('textarea').val()1106 * edit mode (visual): canvas.html()1107 */1108 content = gm.mode !== "visual" ? canvas.find('textarea').val() : canvas.html();1109 // Clean any temp class strings1110 canvas.html(gm.cleanSubstring(gm.options.classRenameSuffix, content, ''));1111 // Clean column markup1112 canvas.find(gm.options.colSelector)1113 .removeAttr("style")1114 .removeAttr("spellcheck")1115 .removeClass("mce-content-body").end()1116 // Clean img markup1117 .find("img")1118 .removeAttr("style")1119 .addClass("img-responsive")1120 .removeAttr("data-cke-saved-src")1121 .removeAttr("data-mce-src").end()1122 // Remove Tools1123 .find("." + gm.options.gmToolClass).remove();1124 // Destroy any RTEs1125 gm.rteControl("stop");1126 gm.log("~~Cleanup Ran~~");1127 };1128 /**1129 * Generic logging function1130 * @method log1131 * @param {object} logvar - The Object or string you want to pass to the console1132 * @returns null1133 * @property {boolean} gm.options.debug1134 */1135 gm.log = function(logvar){1136 if(gm.options.debug){1137 if ((window['console'] !== undefined)) {1138 window.console.log(logvar);1139 }1140 }1141 };1142 // Run initializer1143 gm.init();1144 };1145 /**1146 Options which can be overridden by the .gridmanager() call on the requesting page------------------------------------------------------1147 */1148 $.gridmanager.defaultOptions = {1149 /*1150 General Options---------------1151 */1152 debug: 0,1153 // Are you columns selectable1154 colSelectEnabled: true,1155 // Can add editable regions?1156 editableRegionEnabled: true,1157 // Should we try and automatically create editable regions?1158 autoEdit: true,1159 // URL to save to1160 remoteURL: "/replace-with-your-url",1161 // Custom CSS to load1162 cssInclude: "//maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css",1163 // Filter callback. Callback receives two params: the template grid element and whether is called from the init or deinit method1164 filterCallback: null,1165 /*1166 Canvas---------------1167 */1168 // Canvas ID1169 canvasId: "gm-canvas",1170 /*1171 Control Bar---------------1172 */1173 // Top Control Row ID1174 controlId: "gm-controls",1175 // Move handle class1176 controlMove: 'gm-move',1177 // Editable element toolbar class1178 controlNestedEditable: 'gm-controls-element',1179 // Array of buttons for row templates1180 controlButtons: [[12], [6,6], [4,4,4], [3,3,3,3], [2,2,2,2,2,2], [2,8,2], [4,8], [8,4]],1181 // Custom Global Controls for rows & cols - available props: global_row, global_col1182 customControls: { global_row: [], global_col: [] },1183 // Default control button class1184 controlButtonClass: "btn btn-xs btn-primary",1185 // Default control button icon1186 controlButtonSpanClass: "fa fa-plus-circle",1187 // Control bar RH dropdown markup1188 controlAppend: "<div class='btn-group pull-right'><button title='Edit Source Code' type='button' class='btn btn-xs btn-primary gm-edit-mode'><span class='fa fa-code'></span></button><button title='Preview' type='button' class='btn btn-xs btn-primary gm-preview'><span class='fa fa-eye'></span></button> <div class='dropdown pull-left gm-layout-mode'><button type='button' class='btn btn-xs btn-primary dropdown-toggle' data-toggle='dropdown'><span class='caret'></span></button> <ul class='dropdown-menu' role='menu'><li><a data-width='auto' title='Desktop'><span class='fa fa-desktop'></span> Desktop</a></li><li><a title='Tablet' data-width='768'><span class='fa fa-tablet'></span> Tablet</a></li><li><a title='Phone' data-width='640'><span class='fa fa-mobile-phone'></span> Phone</a></li></ul></div> <button type='button' class='btn btn-xs btn-primary dropdown-toggle' data-toggle='dropdown'><span class='caret'></span><span class='sr-only'>Toggle Dropdown</span></button><ul class='dropdown-menu' role='menu'><li><a title='Save' href='#' class='gm-save'><span class='fa fa-save'></span> Save</a></li><li><a title='Reset Grid' href='#' class='gm-resetgrid'><span class='fa fa-trash-o'></span> Reset</a></li></ul></div>",1189 // Controls for content elements1190 controlContentElem: '<div class="gm-controls-element"> <a class="gm-move fa fa-arrows" href="#" title="Move"></a> <a class="gm-delete fa fa-times" href="#" title="Delete"></a> </div>',1191 /*1192 General editing classes---------------1193 */1194 // Standard edit class, applied to active elements1195 gmEditClass: "gm-editing",1196 // Applied to the currently selected element1197 gmEditClassSelected: "gm-editing-selected",1198 // Editable region class1199 gmEditRegion: "gm-editable-region",1200 // Editable container class1201 gmContentRegion: "gm-content",1202 // Tool bar class which are inserted dynamically1203 gmToolClass: "gm-tools",1204 // Clearing class, used on most toolbars1205 gmClearClass: "clearfix",1206 // generic float left and right1207 gmFloatLeft: "pull-left",1208 gmFloatRight: "pull-right",1209 gmBtnGroup: "btn-group",1210 gmDangerClass: "btn-danger",1211 /*1212 Rows---------------1213 */1214 // Generic row class. change to row--fluid for fluid width in Bootstrap1215 rowClass: "row",1216 // Used to find rows - change to div.row-fluid for fluid width1217 rowSelector: "div.row",1218 // class of background element when sorting rows1219 rowSortingClass: "alert-warning",1220 // Buttons at the top of each row1221 rowButtonsPrepend: [1222 {1223 title:"Move",1224 element: "a",1225 btnClass: "gm-moveRow pull-left",1226 iconClass: "fa fa-arrows "1227 },1228 {1229 title:"New Column",1230 element: "a",1231 btnClass: "gm-addColumn pull-left ",1232 iconClass: "fa fa-plus"1233 },1234 {1235 title:"Row Settings",1236 element: "a",1237 btnClass: "pull-right gm-rowSettings",1238 iconClass: "fa fa-cog"1239 }1240 ],1241 // Buttons at the bottom of each row1242 rowButtonsAppend: [1243 {1244 title:"Remove row",1245 element: "a",1246 btnClass: "pull-right gm-removeRow",1247 iconClass: "fa fa-trash-o"1248 }1249 ],1250 // CUstom row classes - add your own to make them available in the row settings1251 rowCustomClasses: ["example-class","test-class"],1252 /*1253 Columns--------------1254 */1255 // Column Class1256 colClass: "column",1257 // Class to allow content to be draggable1258 contentDraggableClass: 'gm-content-draggable',1259 // Adds any missing classes in columns for muti-device support.1260 addResponsiveClasses: true,1261 // Adds "colClass" to columns if missing: addResponsiveClasses must be true for this to activate1262 addDefaultColumnClass: true,1263 // Generic desktop size layout class1264 colDesktopClass: "col-md-",1265 // Generic tablet size layout class1266 colTabletClass: "col-sm-",1267 // Generic phone size layout class1268 colPhoneClass: "col-xs-",1269 // Wild card column desktop selector1270 colDesktopSelector: "div[class*=col-md-]",1271 // Wildcard column tablet selector1272 colTabletSelector: "div[class*=col-sm-]",1273 // Wildcard column phone selector1274 colPhoneSelector: "div[class*=col-xs-]",1275 // String used to temporarily rename column classes not in use1276 classRenameSuffix: "-clsstmp",1277 // Default layout mode loaded after init1278 layoutDefaultMode: "auto",1279 // Current layout column mode1280 currentClassMode: "",1281 // Additional column class to add (foundation needs columns, bs3 doesn't)1282 colAdditionalClass: "",1283 // Buttons to prepend to each column1284 colButtonsPrepend: [1285 {1286 title:"Move",1287 element: "a",1288 btnClass: "gm-moveCol pull-left",1289 iconClass: "fa fa-arrows "1290 },1291 {1292 title:"Column Settings",1293 element: "a",1294 btnClass: "pull-right gm-colSettings",1295 iconClass: "fa fa-cog"1296 },1297 {1298 title:"Make Column Narrower",1299 element: "a",1300 btnClass: "gm-colDecrease pull-left",1301 iconClass: "fa fa-minus"1302 },1303 {1304 title:"Make Column Wider",1305 element: "a",1306 btnClass: "gm-colIncrease pull-left",1307 iconClass: "fa fa-plus"1308 }1309 ],1310 // Buttons to append to each column1311 colButtonsAppend: [1312 {1313 title:"Add Nested Row",1314 element: "a",1315 btnClass: "pull-left gm-addRow",1316 iconClass: "fa fa-plus-square"1317 },1318 {1319 title:"Remove Column",1320 element: "a",1321 btnClass: "pull-right gm-removeCol",1322 iconClass: "fa fa-trash-o"1323 }1324 ],1325 // CUstom col classes - add your own to make them available in the col settings1326 colCustomClasses: ["example-col-class","test-class"],1327 // Maximum column span value: if you've got a 24 column grid via customised bootstrap, you could set this to 24.1328 colMax: 12,1329 // Column resizing +- value: this is also the colMin value, as columns won't be able to go smaller than this number (otherwise you hit zero and all hell breaks loose)1330 colResizeStep: 1,1331 /*1332 Rich Text Editors---------------1333 */1334 tinymce: {1335 config: {1336 inline: true,1337 plugins: [1338 "advlist autolink lists link image charmap print preview anchor",1339 "searchreplace visualblocks code fullscreen",1340 "insertdatetime media table contextmenu paste"1341 ],1342 toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"1343 }1344 },1345 // Path to CK custom comfiguration1346 ckeditor: {1347 customConfig: ""1348 }1349 };1350 /**1351 * Exposes gridmanager as jquery function1352 * @method gridmanager1353 * @param {object} options1354 * @returns CallExpression1355 */1356 $.fn.gridmanager = function(options){1357 return this.each(function(){1358 var element = $(this);1359 var gridmanager = new $.gridmanager(this, options);1360 element.data('gridmanager', gridmanager);1361 });1362 };1363 /**1364 * General Utility Regex function used to get custom callback attributes1365 * @method regex1366 * @param {} elem1367 * @param {} index1368 * @param {} match1369 * @returns CallExpression1370 */1371 $.expr[':'].regex = function(elem, index, match) {1372 var matchParams = match[3].split(','),1373 validLabels = /^(data|css):/,1374 attr = {1375 method: matchParams[0].match(validLabels) ?1376 matchParams[0].split(':')[0] : 'attr',1377 property: matchParams.shift().replace(validLabels,'')1378 },1379 regexFlags = 'ig',1380 regex = new RegExp(matchParams.join('').replace(/^\s+|\s+$/g,''), regexFlags);1381 return regex.test(jQuery(elem)[attr.method](attr.property));1382 };...
Using AI Code Generation
1var gm = require('devicefarmer-stf').gm;2var adb = require('devicefarmer-stf').adb;3var adbkit = require('adbkit');4var client = adbkit.createClient();5client.listDevices()6 .then(function(devices) {7 devices.forEach(function(device) {8 client.getProperties(device.id)9 .then(adbkit.util.readAll)10 .then(function(output) {11 var properties = adbkit.util.parseProperties(output.toString('utf-8'));12 console.log(properties['ro.product.manufacturer']);13 console.log(properties['ro.product.model']);14 console.log(properties['ro.build.version.release']);15 console.log(properties['ro.build.version.sdk']);16 console.log(properties['ro.product.cpu.abi']);17 console.log(properties['ro.product.cpu.abi2']);18 console.log(properties['ro.product.locale.language']);19 console.log(properties['ro.product.locale.region']);20 console.log(properties['ro.product.brand']);21 console.log(properties['ro.product.name']);22 console.log(properties['ro.product.device']);23 console.log(properties['ro.product.board']);24 console.log(properties['ro.product.manufacturer']);25 console.log(properties['ro.product.model']);26 console.log(properties['ro.product.locale.language']);27 console.log(properties['ro.product.locale.region']);28 console.log(properties['ro.build.version.release']);29 console.log(properties['ro.build.version.sdk']);30 console.log(properties['ro.build.version.codename']);31 console.log(properties['ro.build.version.incremental']);32 console.log(properties['ro.build.version.release']);33 console.log(properties['ro.build.date']);34 console.log(properties['ro.build.date.utc']);35 console.log(properties['ro.build.type']);36 console.log(properties['ro.build.user']);37 console.log(properties['ro.build.host']);38 console.log(properties['ro.build.tags']);39 console.log(properties['ro.build.flavor']);40 console.log(properties['ro.product.cpu.abi']);41 console.log(properties['ro.product.cpu.abi2']);42 console.log(properties['ro.product.locale.language']);43 console.log(properties['ro.product.locale.region']);44 console.log(properties['ro.product.brand']);45 console.log(properties['ro.product.name']);46 console.log(properties['ro.product.device']);47 console.log(properties['ro.product.board']);48 console.log(properties['ro.product.manufacturer']);49 console.log(properties['ro.product.model']);
Using AI Code Generation
1var gm = require('devicefarmer-stf').gm;2var options = {3};4var gm = gm(options);5gm.getDisplayInfo().then(function(res) {6 console.log(res);7});8var gm = require('devicefarmer-stf').gm;9var options = {10};11var gm = gm(options);12gm.getDisplayInfo().then(function(res) {13 console.log(res);14});15var gm = require('devicefarmer-stf').gm;16var options = {17};18var gm = gm(options);19gm.getDisplayInfo().then(function(res) {20 console.log(res);21});22var gm = require('devicefarmer-stf').gm;23var options = {24};25var gm = gm(options);26gm.getDisplayInfo().then(function(res) {27 console.log(res);28});29var gm = require('devicefarmer-stf').gm;30var options = {31};32var gm = gm(options);33gm.getDisplayInfo().then(function(res) {34 console.log(res);35});36var gm = require('devicefar
Using AI Code Generation
1var gm = require('devicefarmer-stf').gm;2gm.open(function(err, device) {3 if (err) {4 console.log('Error: ' + err);5 } else {6 device.screenshot(function(err, image) {7 if (err) {8 console.log('Error: ' + err);9 } else {10 console.log('Screenshot: ' + image);11 }12 });13 }14});15var gm = require('devicefarmer-stf').gm;16gm.open(function(err, device) {17 if (err) {18 console.log('Error: ' + err);19 } else {20 device.screenshot(function(err, image) {21 if (err) {22 console.log('Error: ' + err);23 } else {24 console.log('Screenshot: ' + image);25 }26 });27 }28});29var gm = require('devicefarmer-stf').gm;30gm.open(function(err, device) {31 if (err) {32 console.log('Error: ' + err);33 } else {34 device.screenshot(function(err, image) {35 if (err) {36 console.log('Error: ' + err);37 } else {38 console.log('Screenshot: ' + image);39 }40 });41 }42});43var gm = require('devicefarmer-stf').gm;44gm.open(function(err, device) {45 if (err) {46 console.log('Error: ' + err);47 } else {48 device.screenshot(function(err, image) {49 if (err) {50 console.log('Error: ' + err);51 } else {52 console.log('Screenshot: ' + image);53 }54 });55 }56});57var gm = require('devicefarmer-stf').gm;58gm.open(function(err, device) {59 if (err) {60 console.log('Error: ' + err);61 } else {62 device.screenshot(function(err, image) {63 if (err) {64 console.log('Error: ' +
Using AI Code Generation
1var gm = require('devicefarmer-stf-client').gm2gm('deviceID').getInfo(function(err, info) {3 console.log(info);4});5var gm = require('devicefarmer-stf-client').gm6gm('deviceID').getInfo().then(function(info) {7 console.log(info);8});9var gm = require('devicefarmer-stf-client').gm10gm('deviceID').getInfo(function(err, info) {11 console.log(info);12});13var gm = require('devicefarmer-stf-client').gm14gm('deviceID').getInfo().then(function(info) {15 console.log(info);16});17var gm = require('devicefarmer-stf-client').gm18gm('deviceID').getInfo(function(err, info) {19 console.log(info);20});21var gm = require('devicefarmer-stf-client').gm22gm('deviceID').getInfo().then(function(info) {23 console.log(info);24});25var gm = require('devicefarmer-stf-client').gm26gm('deviceID').getInfo(function(err, info) {27 console.log(info);28});29var gm = require('devicefarmer-stf-client').gm30gm('deviceID').getInfo().then(function(info) {31 console.log(info);32});33var gm = require('devicefarmer-stf-client').gm34gm('deviceID').getInfo(function(err, info) {35 console.log(info);36});37var gm = require('devicefarmer-stf-client').gm38gm('deviceID').get
Using AI Code Generation
1var gm = require('devicefarmer-stf').gm;2var device = gm.getDevice('1234567890');3device.takeScreenshot().then(function (image) {4});5var gm = require('devicefarmer-stf').gm;6var device = gm.getDevice('1234567890');7device.takeScreenshot().then(function (image) {8});9var gm = require('devicefarmer-stf').gm;10var device = gm.getDevice('1234567890');11device.takeScreenshot().then(function (image) {12});13var gm = require('devicefarmer-stf').gm;14var device = gm.getDevice('1234567890');15device.takeScreenshot().then(function (image) {16});17var gm = require('devicefarmer-stf').gm;18var device = gm.getDevice('1234567890');19device.takeScreenshot().then(function (image) {20});21var gm = require('devicefarmer-stf').gm;22var device = gm.getDevice('1234567890');23device.takeScreenshot().then(function (image) {24});25var gm = require('devicefarmer-stf').gm;26var device = gm.getDevice('1234567890');27device.takeScreenshot().then(function (image) {28});29var gm = require('devicefarmer-stf').gm;30var device = gm.getDevice('1234567890');31device.takeScreenshot().then(function (image) {32});
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!