JEMBOT MAWOT Bypass Shell
/**
* @package Joomla.JavaScript
* @copyright Copyright (C) 2005 - 2016 Open Source Matters, Inc. All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
/**
* Options:
* see defaults $.JRepeatable.defaults,
* Options can be set through "data" atribute of the JRepeatable container (see example markup)
*
* Events:
* $('input.form-field-repeatable')
* .on('weready', function(e){
* // fires when JRepeatable initialized
* })
* .on('prepare-template', function(e, template){
* // fires when row template initialized
* })
* .on('prepare-modal', function(e, modal){
* // fires when modal container initialized
* })
* .on('row-add', function(e, row){
* // fires when new row added
* })
* .on('row-remove', function(e, row){
* // fires before row removing
* })
* .on('value-update', function(e, value){
* // fires before when value in hidden input was updated
* });
*
* Dependancies: jQuery, Bootsrap.modal
*
* Example fields initial markup:
*
* <div id="jform_somename_container">
* <div id="jform_somename_modal" class="modal hide">
* <table>
* <thead>
* <tr>
* <th>Field label 1</th>
* <th>Field lable 2</th>
* <th><a href="#" class="add">Add new</a></th>
* </tr>
* </thead>
* <tbody>
* <tr>
* <td><input type="text" name="field1" /></td>
* <td><input type="text" name="field2" /></td>
* <td>
* <a href="#" class="add">Add new after</a>
* <a href="#" class="remove">Remove</a>
* </td>
* </tr>
* </tbody>
* </table>
* <a href="#" class="close-modal">Close</a>
* </div>
* </div>
* <button id="jform_somename_button" >Open modal</button>
* <input type="hidden" name="jform[somename]" id="jform_somename" value=""
* class="form-field-repeatable"
* data-container="#jform_somename_container"
* data-modal-element="#jform_somename_modal"
* data-repeatable-element="table tbody tr"
* data-bt-add="a.add" data-bt-remove="a.remove"
* data-bt-modal-open="#jform_somename_button"
* data-bt-modal-close="a.close-modal"
* data-maximum="3" data-input="#jform_somename"
* />
*
* data-repeatable-element="table tbody tr" - means that <tr> inside <tbody> will be repeatable
*/
;(function($){
"use strict";
$.JRepeatable = function(input, options){
// To avoid scope issues,
var self = this;
//direct call
if(!self || self === window){
return new $.JRepeatable(input, options);
}
self.$input = $(input);
// check if alredy exist
if(self.$input.data("JRepeatable")){
return self;
}
// Add a reverse reference to the DOM object
self.$input.data("JRepeatable", self);
// method initialize
self.init = function(){
// merge options
self.options = $.extend({}, $.JRepeatable.defaults, options);
self.$container = $(self.options.container);
// Move out form the Form container
// for prevent sending to server
$('body').append(self.$container);
// container where the rows is live
self.$rowsContainer = self.$container.find(self.options.repeatableElement).parent();
// prepare modal window
self.prepareModal();
// container for storing info about inputs
self.inputs = [];
self.values = {};
// prepare a row template, and find available field names
self.prepareTemplate();
// check the values and keep it as object
var val = self.$input.val();
if(val){
// value can be not valid JSON
try {
self.values = JSON.parse(val);
} catch (e) {
if(e instanceof SyntaxError){
// guess there a single quote problem
try {
val = val.replace(/'/g, '"').replace(/\\"/g, "\'");// ho ho ho
self.values = JSON.parse(val);
} catch (e) {
// nop
if(window.console){
console.log(e);
}
}
} else if(window.console){
console.log(e);
}
}
}
// so init the form depend from values that we have
self.buildRows();
// bind open the modal
$(document).on('click', self.options.btModalOpen, function (e) {
e.preventDefault();
self.$modalWindow.modal('show');
});
// bind close the modal
self.$modalWindow.on('click', self.options.btModalClose, function (e) {
e.preventDefault();
self.$modalWindow.modal('hide');
// rollback
self.buildRows();
});
// bind save the modaldata
self.$modalWindow.on('click', self.options.btModalSaveData, function (e) {
e.preventDefault();
self.$modalWindow.modal('hide');
self.refreshValue();
});
// bind add button
self.$container.on('click', self.options.btAdd, function (e) {
e.preventDefault();
var after = $(this).parents(self.options.repeatableElement);
if(!after.length){
after = null;
}
self.addRow(after);
});
// bind remove button
self.$container.on('click', self.options.btRemove, function (e) {
e.preventDefault();
var row = $(this).parents(self.options.repeatableElement);
self.removeRow(row);
});
// tell all that we a ready
self.$input.trigger('weready');
};
// prepare a template that we will use for repeating
self.prepareTemplate = function(){
//find available
var $rows = self.$container.find(self.options.repeatableElement);
var $row = $($rows.get(0));
// clear scripts that can be attached to the fields
try {
self.clearScripts($row);
} catch (e) {
if(window.console){
console.log(e);
}
}
var inputs = $row.find('*[name]');
//keep the name and type for each
for(var i = 0, l = inputs.length; i < l; i++){
var name = $(inputs[i]).attr('name');
// check if alredy exist, for radio case
if(self.values[name]){
continue;
}
self.inputs.push({
name: name,
type: $(inputs[i]).attr('type') || inputs[i].tagName.toLowerCase()
});
// initialize values
self.values[name] = [];
}
// keep template
self.template = $row.prop('outerHTML');
// remove
$rows.remove();
// tell all that the template ready
self.$input.trigger('prepare-template', self.template);
};
// prepare modal window
self.prepareModal = function(){
var modalEl = $(self.options.modalElement);
// fix modal style
modalEl.css({
position: 'absolute',
width: 'auto',
'max-width': '100%'
});
modalEl.on('shown', function () {
self.resizeModal();
});
$(window).resize(function() {
self.resizeModal();
});
// init bootstrap modal
self.$modalWindow = modalEl.modal({show: false, backdrop: 'static'});
// tell all that the modal are ready
self.$input.trigger('prepare-modal', self.$modalWindow);
};
//resize and count position for the modal popup
self.resizeModal = function (){
if(!self.$modalWindow.is(':visible')){
// do nothing with hidden
return;
}
var docHalfWidth = $(document).width() / 2,
modalHalfWidth = self.$modalWindow.width() / 2,
rowsHalfWidth = self.$rowsContainer.width() / 2,
marginLeft = modalHalfWidth >= docHalfWidth ? 0 : -modalHalfWidth,
left = marginLeft ? '50%' : 0,
top = $(document).scrollTop() + $(window).height() * 0.2;//20% from top of visible win
self.$modalWindow.css({
top: top,
left: left,
'margin-left': marginLeft,
overflow: rowsHalfWidth > modalHalfWidth ? 'auto' : 'visible'
});
};
// build rows
self.buildRows = function(){
// clean up any old
var $oldRows = self.$rowsContainer.children();
if($oldRows.length){
self.removeRow($oldRows);
}
// go through values and add a new copy
// but make sure that at least one will be added
var count = self.values[Object.keys(self.values)[0]].length || 1,
row = null;
for(var i = 0; i < count; i++){
row = self.addRow(row, i);
}
};
// add new row
self.addRow = function(after, valueKey){
// count how much we already have
var count = self.$container.find(self.options.repeatableElement).length;
if(count >= self.options.maximum){
return null;
}
// make new from template
var row = $.parseHTML(self.template);
//add to container
if(after){
$(after).after(row);
} else {
self.$rowsContainer.append(row);
}
var $row = $(row);
// fix names and id`s
self.fixUniqueAttributes($row, count + 1);
// set values
if(valueKey !== null && valueKey !== undefined){
for(var i = 0, l = self.inputs.length; i < l; i++){
var name = self.inputs[i].name,
type = self.inputs[i].type,
value = null;
if(self.values[name]){
value = self.values[name][valueKey];
}
// skip undefined
if(value === null || value === undefined){
continue;
}
if(type === 'radio'){
$row.find('*[name*="'+name+'"][value="' + value + '"]').attr('checked', 'checked');
}else if(type === 'checkbox'){
// check if there a multiple
if(value.length){
for(var v = 0, vl = value.length; v < vl; v++){
$row.find('*[name*="'+name+'"][value="' + value[v] + '"]').attr('checked', 'checked');
}
} else {
$row.find('*[name*="'+name+'"][value="' + value + '"]').attr('checked', 'checked');
}
} else {
$row.find('*[name*="'+name+'"]').val(value);
}
}
}
// try find out with related scripts,
// tricky thing, so be careful
try {
self.fixScripts($row);
} catch (e) {
if(window.console){
console.log(e);
}
}
// tell all about new row
self.$input.trigger('row-add', $row);
return $row;
};
// remove row from container
self.removeRow = function(row){
// tell all about row removing
self.$input.trigger('row-remove', row);
$(row).remove();
};
//fix names ind id`s for field that in $row
self.fixUniqueAttributes = function($row, count){
//all elements that have a "id" attribute
var haveIds = $row.find('*[id]');
self.increaseAttrName(haveIds, 'id', count);
// all labels that have a "for" attribute
var haveFor = $row.find('label[for]');
self.increaseAttrName(haveFor, 'for', count);
// all inputs that have a "name" attribute
var haveName = $row.find('*[name]');
self.increaseAttrName(haveName, 'name', count);
};
// increase attribute name like: attribute_value + '-' + count
self.increaseAttrName = function (elements, attr, count){
for(var i = 0, l = elements.length; i < l; i++){
var $el = $(elements[i]);
var oldValue = $el.attr(attr);
// set new
$el.attr(attr, oldValue + '-' + count);
}
};
// refresh value in the main input
self.refreshValue = function(){
var $rows = self.$container.find(self.options.repeatableElement);
// reset existing
self.values = {};
// go through available input names
for(var i = 0, l = self.inputs.length; i < l; i++){
var name = self.inputs[i].name,
type = self.inputs[i].type;
// init new
self.values[name] = [];
// find all inputs and take their values
for(var r = 0, rl = $rows.length; r < rl; r++){
var $row = $($rows[r]),
val = null;
if(type === 'radio'){
val = $row.find('*[name*="'+name+'"]:checked').val();
}else if(type === 'checkbox'){
var checked = $row.find('*[name*="'+name+'"]:checked');
// test for multiple
if(checked.length > 1){
val = [];
for(var c = 0, cl = checked.length; c < cl; c++){
val.push($(checked[c]).val());
}
} else {
// single checkbox
val = checked.val();
}
}else{
val = $row.find('*[name*="'+name+'"]').val();
}
val = val === null ? '' : val;
self.values[name].push(val)
}
}
// put in to the main input
self.$input.val(JSON.stringify(self.values));
// tell all about value changed
self.$input.trigger('value-update', self.values);
};
// remove scripts attached to fields
self.clearScripts = function($row){
// destroy chosen if any
if($.fn.chosen){
$row.find('select.chzn-done').chosen('destroy');
}
// colorpicker
if($.fn.minicolors){
$row.find('.minicolors input').each(function(){
$(this).minicolors('destroy', $(this));
});
}
};
// method for hack the scripts that can be related
// to the one of field that in given $row
self.fixScripts = function($row){
// chosen hack
if($.fn.chosen){
$row.find('select').chosen()
}
//color picker
$row.find('.minicolors').each(function() {
var $el = $(this);
$el.minicolors({
control: $el.attr('data-control') || 'hue',
position: $el.attr('data-position') || 'right',
theme: 'bootstrap'
});
});
// fix media field
$row.find('a[onclick*="jInsertFieldValue"]').each(function(){
var $el = $(this),
inputId = $el.siblings('input[type="text"]').attr('id'),
$select = $el.prev(),
oldHref = $select.attr('href');
// update the clear button
$el.attr('onclick', "jInsertFieldValue('', '" + inputId + "');return false;")
// update select button
$select.attr('href', oldHref.replace(/&fieldid=(.+)&/, '&fieldid=' + inputId + '&'));
});
// another modals
if(window.SqueezeBox){
SqueezeBox.assign($row.find('a.modal').get(), {parse: 'rel'});
}
};
// Run initializer
self.init();
};
// defaults
$.JRepeatable.defaults = {
modalElement: "#modal-container", // id of the modal container
btModalOpen: "#open-modal", // id of the button for initiate the modal window
btModalClose: ".close-modal", // button for close the modal window, and rollback all changes
btModalSaveData: ".save-modal-data", // button for close the modal window, and keep the all changes
btAdd: "a.add", // button selector for "add" action
btRemove: "a.remove",// button selector for "remove" action
maximum: 10, // maximum repeating
repeatableElement: "table tbody tr"
};
$.fn.JRepeatable = function(options){
return this.each(function(){
var options = options || {},
data = $(this).data();
for (var p in data) {
// check options in the element
if (data.hasOwnProperty(p)) {
options[p] = data[p];
}
}
new $.JRepeatable(this, options);
});
};
// initialise all available
// wait when all will be loaded, important for scripts fix
$(window).on('load', function(){
$('input.form-field-repeatable').JRepeatable();
})
})(jQuery);
xxxxx1.0, XXX xxxx