1// the semi-colon before function invocation is a safety net against concatenated 2// scripts and/or other plugins which may not be closed properly. 3;(function($, window, document, undefined) { 4 5 // undefined is used here as the undefined global variable in ECMAScript 3 is 6 // mutable (ie. it can be changed by someone else). undefined isn't really being 7 // passed in so we can ensure the value of it is truly undefined. In ES5, undefined 8 // can no longer be modified. 9 10 // window and document are passed through as local variable rather than global 11 // as this (slightly) quickens the resolution process and can be more efficiently 12 // minified (especially when both are regularly referenced in your plugin). 13 14 // Create the defaults once 15 var pluginName = 'itemsList', 16 defaults = { 17 add_item_button: '.cdb-add-item', 18 remove_item_button: '.cdb-remove-item', 19 items_wrapper: '.cdb-items', 20 item: '.cdb-item', 21 sort_handle: '.cdb-sort-handle', 22 fields: [ 23 {selector: 'input[type=text]', type: 'text', value: ''}, 24 {selector: 'textarea', type: 'textarea', value: ''}, 25 {selector: 'input[type=checkbox]', type: 'checkbox', value: false} 26 ], 27 index_pos: 0, 28 onAdd: function() {}, 29 onRemove: function() {}, 30 onReorder: function() {} 31 }; 32 33 // The actual plugin constructor 34 function Plugin(element, options) { 35 this.element = element; 36 // jQuery has an extend method which merges the contents of two or 37 // more objects, storing the result in the first object. The first object 38 // is generally empty as we don't want to alter the default options for 39 // future instances of the plugin 40 this._defaults = defaults; 41 this._name = pluginName; 42 43 this.settings = $.extend({}, defaults, options); 44 this.init(); 45 46// if (methodOrOptions === 'init') { 47// couponDB.main.log(pluginName + ': init'); 48// this.settings = $.extend({}, defaults, options); 49// this.init(); 50// } else if (typeof this[methodOrOptions] === 'function') { 51// couponDB.main.log(pluginName + ': Calling ' + methodOrOptions); 52// this[methodOrOptions](options); 53// } 54 } 55 56 // Avoid Plugin.prototype conflicts 57 $.extend(Plugin.prototype, { 58 init: function() { 59 // Place initialization logic here 60 // You already have access to the DOM element and 61 // the options via the instance, e.g. this.element 62 // and this.settings 63 // you can add more functions like the one below and 64 // call them like so: this.yourOtherFunction(this.element, this.settings). 65 66 var plugin = this, 67 element = this.element, 68 settings = this.settings; 69 70 // add item 71 $(element).siblings(settings.add_item_button).on('click', function() { 72 plugin.add(); 73 return false; 74 }); 75 76 // remove item 77 $(element).on('click', settings.remove_item_button, function() { 78 plugin.remove(this); 79 return false; 80 }); 81 82 $(element).sortable({ 83 handle: settings.sort_handle, 84 stop: function(e, ui) { 85 plugin.reorder(); 86 } 87 }); 88 }, 89 /** 90 * Add item 91 * 92 * @param {array} items [{selector, type, value}, {selector, type, value}, ...] 93 * @param {int} itemIndex 94 * @returns {undefined} 95 */ 96 add: function(args) { 97 var $element = $(this.element), 98 settings = this.settings, 99 items = typeof args !== 'undefined' && args.fields ? args.fields : settings.fields, 100 itemIndex = typeof args !== 'undefined' && typeof args.index !== 'undefined' ? args.index : false, 101 $newItem = $element.find(settings.item).last().clone(), 102 i = -1; 103 104 for (var key in items) { 105 var item = items[key], 106 $input = $newItem.find(item.selector), 107 name = $input.attr('name'); 108 109 i = -1; 110 111 if (name) { 112 var newItemName = $input.attr('name').replace(/(\d+)/g, function(match) { 113 i++; 114 if (i === settings.index_pos) { 115 return itemIndex === false ? (parseInt(match) + 1) : itemIndex; 116 } 117 return match; 118 }); 119 120 $input.attr('name', newItemName); 121 } 122 123 switch (item.type) { 124 case 'checkbox': 125 $input.prop('checked', item.value); 126 break; 127 case 'text_block': 128 $input.text(item.value); 129 break; 130 case 'html_block': 131 $input.html(item.value); 132 break; 133 case 'text': 134 case 'textarea': 135 default: 136 $input.val(item.value); 137 } 138 } 139 140 $element.append($newItem); 141 142 if (typeof args === 'undefined' || typeof args.internalCall === 'undefined' || !args.internalCall) { 143 settings.onAdd($newItem); 144 } 145 146 couponDB.main.log('couponsList: add'); 147 }, 148 remove: function(button) { 149 var plugin = this, 150 element = this.element, 151 settings = this.settings, 152 $this = $(button), 153 $container = $this.closest(element), 154 $items = $container.find(settings.item), 155 $item = $this.closest(settings.item); 156 157 if ($items.length < 2) { 158 plugin.add({index: 0, internalCall: true}); 159 } 160 161 $item.remove(); 162 163 settings.onRemove($container); 164 165 couponDB.main.log('couponsList: remove'); 166 }, 167 clear: function() { 168 var $items = $(this.element).find(this.settings.item), 169 items_count = $items.length, 170 plugin = this; 171 172 $(this.element).find(this.settings.item).each(function(index, item) { 173 if (items_count === index + 1) { 174 plugin.add({index: 0, internalCall: true}); 175 } 176 $(item).remove(); 177 }); 178 }, 179 reorder: function() { 180 var settings = this.settings, 181 $container = $(this.element); 182 183 $container.find(this.settings.item).each(function(index, item) { 184 for (var key in settings.fields) { 185 var field = settings.fields[key], 186 $field = $(item).find(field.selector), 187 name = $field.attr('name'); 188 189 var i = -1; 190 191 if (name) { 192 var newItemName = name.replace(/(\d+)/g, function(match) { 193 i++; 194 if (i === settings.index_pos) { 195 return index; 196 } 197 return match; 198 }); 199 200/* var currentItemId = parseInt(name.replace(/^\D+/g, '')), 201 newItemName = name.replace(currentItemId, index);*/ 202 203 $field.attr('name', newItemName); 204 } 205 } 206 }); 207 208 settings.onReorder($container); 209 210 couponDB.main.log('couponsList: reorder'); 211 } 212 }); 213 214 // A really lightweight plugin wrapper around the constructor, 215 // preventing against multiple instantiations 216 $.fn[pluginName] = function(method, options) { 217 this.each(function() { 218 var instance = $.data(this, "plugin_" + pluginName); 219 if (!instance) { 220 couponDB.main.log(pluginName + ': init'); 221 $.data(this, "plugin_" + pluginName, new Plugin(this, options)); 222 } else if (typeof instance[method] === 'function') { 223 couponDB.main.log(pluginName + ': Calling ' + method); 224 instance[method](options); 225 } else { 226 couponDB.main.log(pluginName + ': Can not call method ' + method); 227 } 228 }); 229 230 // chain jQuery functions 231 return this; 232 }; 233 234})(jQuery, window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.