",{text:b})}}},functionAttributes:["beforeOpen","afterOpen","beforeContent","afterContent","beforeClose","afterClose"],readElementConfig:function(b,c){var d=this,e=new RegExp("^data-"+c+"-(.*)"),f={};return b&&b.attributes&&a.each(b.attributes,function(){var b=this.name.match(e);if(b){var c=this.value,g=a.camelCase(b[1]);if(a.inArray(g,d.functionAttributes)>=0)c=new Function(c);else try{c=JSON.parse(c)}catch(h){}f[g]=c}}),f},extend:function(b,c){var d=function(){this.constructor=b};return d.prototype=this.prototype,b.prototype=new d,b.__super__=this.prototype,a.extend(b,this,c),b.defaults=b.prototype,b},attach:function(b,c,d){var e=this;"object"!=typeof c||c instanceof a!=!1||d||(d=c,c=void 0),d=a.extend({},d);var f,g=d.namespace||e.defaults.namespace,h=a.extend({},e.defaults,e.readElementConfig(b[0],g),d),i=function(g){var i=a(g.currentTarget),j=a.extend({$source:b,$currentTarget:i},e.readElementConfig(b[0],h.namespace),e.readElementConfig(g.currentTarget,h.namespace),d),k=f||i.data("featherlight-persisted")||new e(c,j);"shared"===k.persist?f=k:k.persist!==!1&&i.data("featherlight-persisted",k),j.$currentTarget.blur&&j.$currentTarget.blur(),k.open(g)};return b.on(h.openTrigger+"."+h.namespace,h.filter,i),i},current:function(){var a=this.opened();return a[a.length-1]||null},opened:function(){var b=this;return f(),a.grep(e,function(a){return a instanceof b})},close:function(a){var b=this.current();return b?b.close(a):void 0},_onReady:function(){var b=this;b.autoBind&&(a(b.autoBind).each(function(){b.attach(a(this))}),a(document).on("click",b.autoBind,function(c){if(!c.isDefaultPrevented()){var d=b.attach(a(c.currentTarget));d(c)}}))},_callbackChain:{onKeyUp:function(b,c){return 27===c.keyCode?(this.closeOnEsc&&a.featherlight.close(c),!1):b(c)},beforeOpen:function(b,c){return a(document.documentElement).addClass("with-featherlight"),this._previouslyActive=document.activeElement,this._$previouslyTabbable=a("a, input, select, textarea, iframe, button, iframe, [contentEditable=true]").not("[tabindex]").not(this.$instance.find("button")),this._$previouslyWithTabIndex=a("[tabindex]").not('[tabindex="-1"]'),this._previousWithTabIndices=this._$previouslyWithTabIndex.map(function(b,c){return a(c).attr("tabindex")}),this._$previouslyWithTabIndex.add(this._$previouslyTabbable).attr("tabindex",-1),document.activeElement.blur&&document.activeElement.blur(),b(c)},afterClose:function(c,d){var e=c(d),f=this;return this._$previouslyTabbable.removeAttr("tabindex"),this._$previouslyWithTabIndex.each(function(b,c){a(c).attr("tabindex",f._previousWithTabIndices[b])}),this._previouslyActive.focus(),0===b.opened().length&&a(document.documentElement).removeClass("with-featherlight"),e},onResize:function(a,b){return this.resize(this.$content.naturalWidth,this.$content.naturalHeight),a(b)},afterContent:function(a,b){var c=a(b);return this.$instance.find("[autofocus]:not([disabled])").focus(),this.onResize(b),c}}}),a.featherlight=b,a.fn.featherlight=function(a,c){return b.attach(this,a,c),this},a(document).ready(function(){b._onReady()})}(jQuery);
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/nicefileinput.js b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/nicefileinput.js
new file mode 100644
index 00000000..5a19796c
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/nicefileinput.js
@@ -0,0 +1 @@
+!function(a){a.fn.nicefileinput=function(b){var c={label:"Browse...",fullPath:!1};return b&&a.extend(c,b),this.each(function(){var b=this;if(void 0===a(b).attr("data-styled")){var d=Math.round(1e4*Math.random()),e=new Date,f=e.getTime()+d.toString(),g=a('
').css({display:"block","float":"left",margin:0,padding:"0 5px"}).addClass("NFI-filename NFI"+f),h=a("
").css({overflow:"hidden",position:"relative",display:"block","float":"left","white-space":"nowrap","text-align":"center"}).addClass("NFI-button NFI"+f).html(c.label);a(b).after(g),a(b).wrap(h),a(".NFI"+f).wrapAll('
'),a(".NFI-wrapper").css({overflow:"auto",display:"inline-block"}),a("#NFI-wrapper-"+f).addClass(a(b).attr("class")),a(b).css({opacity:0,position:"absolute",border:"none",margin:0,padding:0,top:0,right:0,cursor:"pointer",height:"60px"}).addClass("NFI-current"),a(b).on("change",function(){var d=a(b).val();if(c.fullPath)g.val(d);else{var e=d.split(/[/\\]/);g.val(e[e.length-1])}}),a(b).attr("data-styled",!0)}})}}(jQuery);
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/select.js b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/select.js
new file mode 100644
index 00000000..0266f65c
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/select.js
@@ -0,0 +1,3 @@
+/* Chosen v1.8.2 | (c) 2011-2018 by Harvest | MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md */
+
+(function(){var t,e,s,i,n=function(t,e){return function(){return t.apply(e,arguments)}},r=function(t,e){function s(){this.constructor=t}for(var i in e)o.call(e,i)&&(t[i]=e[i]);return s.prototype=e.prototype,t.prototype=new s,t.__super__=e.prototype,t},o={}.hasOwnProperty;(i=function(){function t(){this.options_index=0,this.parsed=[]}return t.prototype.add_node=function(t){return"OPTGROUP"===t.nodeName.toUpperCase()?this.add_group(t):this.add_option(t)},t.prototype.add_group=function(t){var e,s,i,n,r,o;for(e=this.parsed.length,this.parsed.push({array_index:e,group:!0,label:t.label,title:t.title?t.title:void 0,children:0,disabled:t.disabled,classes:t.className}),o=[],s=0,i=(r=t.childNodes).length;s
"+t.group_label+""+t.html:t.html},t.prototype.mouse_enter=function(){return this.mouse_on_container=!0},t.prototype.mouse_leave=function(){return this.mouse_on_container=!1},t.prototype.input_focus=function(t){if(this.is_multiple){if(!this.active_field)return setTimeout(function(t){return function(){return t.container_mousedown()}}(this),50)}else if(!this.active_field)return this.activate_field()},t.prototype.input_blur=function(t){if(!this.mouse_on_container)return this.active_field=!1,setTimeout(function(t){return function(){return t.blur_test()}}(this),100)},t.prototype.label_click_handler=function(t){return this.is_multiple?this.container_mousedown(t):this.activate_field()},t.prototype.results_option_build=function(t){var e,s,i,n,r,o,h;for(e="",h=0,n=0,r=(o=this.results_data).length;n=this.max_shown_results));n++);return e},t.prototype.result_add_option=function(t){var e,s;return t.search_match&&this.include_option_in_results(t)?(e=[],t.disabled||t.selected&&this.is_multiple||e.push("active-result"),!t.disabled||t.selected&&this.is_multiple||e.push("disabled-result"),t.selected&&e.push("result-selected"),null!=t.group_array_index&&e.push("group-option"),""!==t.classes&&e.push(t.classes),s=document.createElement("li"),s.className=e.join(" "),s.style.cssText=t.style,s.setAttribute("data-option-array-index",t.array_index),s.innerHTML=t.highlighted_html||t.html,t.title&&(s.title=t.title),this.outerHTML(s)):""},t.prototype.result_add_group=function(t){var e,s;return(t.search_match||t.group_match)&&t.active_options>0?((e=[]).push("group-result"),t.classes&&e.push(t.classes),s=document.createElement("li"),s.className=e.join(" "),s.innerHTML=t.highlighted_html||this.escape_html(t.label),t.title&&(s.title=t.title),this.outerHTML(s)):""},t.prototype.results_update_field=function(){if(this.set_default_text(),this.is_multiple||this.results_reset_cleanup(),this.result_clear_highlight(),this.results_build(),this.results_showing)return this.winnow_results()},t.prototype.reset_single_select_options=function(){var t,e,s,i,n;for(n=[],t=0,e=(s=this.results_data).length;t"+this.escape_html(e)+""+this.escape_html(d)),null!=_&&(_.group_match=!0)):null!=n.group_array_index&&this.results_data[n.group_array_index].search_match&&(n.search_match=!0)));return this.result_clear_highlight(),c<1&&o.length?(this.update_results_content(""),this.no_results(o)):(this.update_results_content(this.results_option_build()),this.winnow_results_set_highlight())},t.prototype.get_search_regex=function(t){var e,s;return s=this.search_contains?t:"(^|\\s|\\b)"+t+"[^\\s]*",this.enable_split_word_search||this.search_contains||(s="^"+s),e=this.case_sensitive_search?"":"i",new RegExp(s,e)},t.prototype.search_string_match=function(t,e){var s;return s=e.exec(t),!this.search_contains&&(null!=s?s[1]:void 0)&&(s.index+=1),s},t.prototype.choices_count=function(){var t,e,s;if(null!=this.selected_option_count)return this.selected_option_count;for(this.selected_option_count=0,t=0,e=(s=this.form_field.options).length;t0?this.keydown_backstroke():this.pending_backstroke||(this.result_clear_highlight(),this.results_search());break;case 13:t.preventDefault(),this.results_showing&&this.result_select(t);break;case 27:this.results_showing&&this.results_hide();break;case 9:case 16:case 17:case 18:case 38:case 40:case 91:break;default:this.results_search()}},t.prototype.clipboard_event_checker=function(t){if(!this.is_disabled)return setTimeout(function(t){return function(){return t.results_search()}}(this),50)},t.prototype.container_width=function(){return null!=this.options.width?this.options.width:this.form_field.offsetWidth+"px"},t.prototype.include_option_in_results=function(t){return!(this.is_multiple&&!this.display_selected_options&&t.selected)&&(!(!this.display_disabled_options&&t.disabled)&&!t.empty)},t.prototype.search_results_touchstart=function(t){return this.touch_started=!0,this.search_results_mouseover(t)},t.prototype.search_results_touchmove=function(t){return this.touch_started=!1,this.search_results_mouseout(t)},t.prototype.search_results_touchend=function(t){if(this.touch_started)return this.search_results_mouseup(t)},t.prototype.outerHTML=function(t){var e;return t.outerHTML?t.outerHTML:((e=document.createElement("div")).appendChild(t),e.innerHTML)},t.prototype.get_single_html=function(){return'\n '+this.default_text+' \n
\n \n'},t.prototype.get_multi_html=function(){return'\n'},t.prototype.get_no_results_html=function(t){return'\n '+this.results_none_found+" "+this.escape_html(t)+" \n "},t.browser_is_supported=function(){return"Microsoft Internet Explorer"===window.navigator.appName?document.documentMode>=8:!(/iP(od|hone)/i.test(window.navigator.userAgent)||/IEMobile/i.test(window.navigator.userAgent)||/Windows Phone/i.test(window.navigator.userAgent)||/BlackBerry/i.test(window.navigator.userAgent)||/BB10/i.test(window.navigator.userAgent)||/Android.*Mobile/i.test(window.navigator.userAgent))},t.default_multiple_text="Select Some Options",t.default_single_text="Select an Option",t.default_no_result_text="No results match",t}(),(t=jQuery).fn.extend({chosen:function(i){return e.browser_is_supported()?this.each(function(e){var n,r;r=(n=t(this)).data("chosen"),"destroy"!==i?r instanceof s||n.data("chosen",new s(this,i)):r instanceof s&&r.destroy()}):this}}),s=function(s){function n(){return n.__super__.constructor.apply(this,arguments)}return r(n,e),n.prototype.setup=function(){return this.form_field_jq=t(this.form_field),this.current_selectedIndex=this.form_field.selectedIndex},n.prototype.set_up_html=function(){var e,s;return(e=["chosen-container"]).push("chosen-container-"+(this.is_multiple?"multi":"single")),this.inherit_select_classes&&this.form_field.className&&e.push(this.form_field.className),this.is_rtl&&e.push("chosen-rtl"),s={"class":e.join(" "),title:this.form_field.title},this.form_field.id.length&&(s.id=this.form_field.id.replace(/[^\w]/g,"_")+"_chosen"),this.container=t("
",s),this.container.width(this.container_width()),this.is_multiple?this.container.html(this.get_multi_html()):this.container.html(this.get_single_html()),this.form_field_jq.hide().after(this.container),this.dropdown=this.container.find("div.chosen-drop").first(),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chosen-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chosen-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chosen-search").first(),this.selected_item=this.container.find(".chosen-single").first()),this.results_build(),this.set_tab_index(),this.set_label_behavior()},n.prototype.on_ready=function(){return this.form_field_jq.trigger("chosen:ready",{chosen:this})},n.prototype.register_observers=function(){return this.container.on("touchstart.chosen",function(t){return function(e){t.container_mousedown(e)}}(this)),this.container.on("touchend.chosen",function(t){return function(e){t.container_mouseup(e)}}(this)),this.container.on("mousedown.chosen",function(t){return function(e){t.container_mousedown(e)}}(this)),this.container.on("mouseup.chosen",function(t){return function(e){t.container_mouseup(e)}}(this)),this.container.on("mouseenter.chosen",function(t){return function(e){t.mouse_enter(e)}}(this)),this.container.on("mouseleave.chosen",function(t){return function(e){t.mouse_leave(e)}}(this)),this.search_results.on("mouseup.chosen",function(t){return function(e){t.search_results_mouseup(e)}}(this)),this.search_results.on("mouseover.chosen",function(t){return function(e){t.search_results_mouseover(e)}}(this)),this.search_results.on("mouseout.chosen",function(t){return function(e){t.search_results_mouseout(e)}}(this)),this.search_results.on("mousewheel.chosen DOMMouseScroll.chosen",function(t){return function(e){t.search_results_mousewheel(e)}}(this)),this.search_results.on("touchstart.chosen",function(t){return function(e){t.search_results_touchstart(e)}}(this)),this.search_results.on("touchmove.chosen",function(t){return function(e){t.search_results_touchmove(e)}}(this)),this.search_results.on("touchend.chosen",function(t){return function(e){t.search_results_touchend(e)}}(this)),this.form_field_jq.on("chosen:updated.chosen",function(t){return function(e){t.results_update_field(e)}}(this)),this.form_field_jq.on("chosen:activate.chosen",function(t){return function(e){t.activate_field(e)}}(this)),this.form_field_jq.on("chosen:open.chosen",function(t){return function(e){t.container_mousedown(e)}}(this)),this.form_field_jq.on("chosen:close.chosen",function(t){return function(e){t.close_field(e)}}(this)),this.search_field.on("blur.chosen",function(t){return function(e){t.input_blur(e)}}(this)),this.search_field.on("keyup.chosen",function(t){return function(e){t.keyup_checker(e)}}(this)),this.search_field.on("keydown.chosen",function(t){return function(e){t.keydown_checker(e)}}(this)),this.search_field.on("focus.chosen",function(t){return function(e){t.input_focus(e)}}(this)),this.search_field.on("cut.chosen",function(t){return function(e){t.clipboard_event_checker(e)}}(this)),this.search_field.on("paste.chosen",function(t){return function(e){t.clipboard_event_checker(e)}}(this)),this.is_multiple?this.search_choices.on("click.chosen",function(t){return function(e){t.choices_click(e)}}(this)):this.container.on("click.chosen",function(t){t.preventDefault()})},n.prototype.destroy=function(){return t(this.container[0].ownerDocument).off("click.chosen",this.click_test_action),this.form_field_label.length>0&&this.form_field_label.off("click.chosen"),this.search_field[0].tabIndex&&(this.form_field_jq[0].tabIndex=this.search_field[0].tabIndex),this.container.remove(),this.form_field_jq.removeData("chosen"),this.form_field_jq.show()},n.prototype.search_field_disabled=function(){return this.is_disabled=this.form_field.disabled||this.form_field_jq.parents("fieldset").is(":disabled"),this.container.toggleClass("chosen-disabled",this.is_disabled),this.search_field[0].disabled=this.is_disabled,this.is_multiple||this.selected_item.off("focus.chosen",this.activate_field),this.is_disabled?this.close_field():this.is_multiple?void 0:this.selected_item.on("focus.chosen",this.activate_field)},n.prototype.container_mousedown=function(e){var s;if(!this.is_disabled)return!e||"mousedown"!==(s=e.type)&&"touchstart"!==s||this.results_showing||e.preventDefault(),null!=e&&t(e.target).hasClass("search-choice-close")?void 0:(this.active_field?this.is_multiple||!e||t(e.target)[0]!==this.selected_item[0]&&!t(e.target).parents("a.chosen-single").length||(e.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),t(this.container[0].ownerDocument).on("click.chosen",this.click_test_action),this.results_show()),this.activate_field())},n.prototype.container_mouseup=function(t){if("ABBR"===t.target.nodeName&&!this.is_disabled)return this.results_reset(t)},n.prototype.search_results_mousewheel=function(t){var e;if(t.originalEvent&&(e=t.originalEvent.deltaY||-t.originalEvent.wheelDelta||t.originalEvent.detail),null!=e)return t.preventDefault(),"DOMMouseScroll"===t.type&&(e*=40),this.search_results.scrollTop(e+this.search_results.scrollTop())},n.prototype.blur_test=function(t){if(!this.active_field&&this.container.hasClass("chosen-container-active"))return this.close_field()},n.prototype.close_field=function(){return t(this.container[0].ownerDocument).off("click.chosen",this.click_test_action),this.active_field=!1,this.results_hide(),this.container.removeClass("chosen-container-active"),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale(),this.search_field.blur()},n.prototype.activate_field=function(){if(!this.is_disabled)return this.container.addClass("chosen-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},n.prototype.test_active_click=function(e){var s;return(s=t(e.target).closest(".chosen-container")).length&&this.container[0]===s[0]?this.active_field=!0:this.close_field()},n.prototype.results_build=function(){return this.parsing=!0,this.selected_option_count=null,this.results_data=i.select_to_array(this.form_field),this.is_multiple?this.search_choices.find("li.search-choice").remove():this.is_multiple||(this.single_set_selected_text(),this.disable_search||this.form_field.options.length<=this.disable_search_threshold?(this.search_field[0].readOnly=!0,this.container.addClass("chosen-container-single-nosearch")):(this.search_field[0].readOnly=!1,this.container.removeClass("chosen-container-single-nosearch"))),this.update_results_content(this.results_option_build({first:!0})),this.search_field_disabled(),this.show_search_field_default(),this.search_field_scale(),this.parsing=!1},n.prototype.result_do_highlight=function(t){var e,s,i,n,r;if(t.length){if(this.result_clear_highlight(),this.result_highlight=t,this.result_highlight.addClass("highlighted"),i=parseInt(this.search_results.css("maxHeight"),10),r=this.search_results.scrollTop(),n=i+r,s=this.result_highlight.position().top+this.search_results.scrollTop(),(e=s+this.result_highlight.outerHeight())>=n)return this.search_results.scrollTop(e-i>0?e-i:0);if(s0)return this.form_field_label.on("click.chosen",this.label_click_handler)},n.prototype.show_search_field_default=function(){return this.is_multiple&&this.choices_count()<1&&!this.active_field?(this.search_field.val(this.default_text),this.search_field.addClass("default")):(this.search_field.val(""),this.search_field.removeClass("default"))},n.prototype.search_results_mouseup=function(e){var s;if((s=t(e.target).hasClass("active-result")?t(e.target):t(e.target).parents(".active-result").first()).length)return this.result_highlight=s,this.result_select(e),this.search_field.focus()},n.prototype.search_results_mouseover=function(e){var s;if(s=t(e.target).hasClass("active-result")?t(e.target):t(e.target).parents(".active-result").first())return this.result_do_highlight(s)},n.prototype.search_results_mouseout=function(e){if(t(e.target).hasClass("active-result")||t(e.target).parents(".active-result").first())return this.result_clear_highlight()},n.prototype.choice_build=function(e){var s,i;return s=t(" ",{"class":"search-choice"}).html(""+this.choice_label(e)+" "),e.disabled?s.addClass("search-choice-disabled"):((i=t(" ",{"class":"search-choice-close","data-option-array-index":e.array_index})).on("click.chosen",function(t){return function(e){return t.choice_destroy_link_click(e)}}(this)),s.append(i)),this.search_container.before(s)},n.prototype.choice_destroy_link_click=function(e){if(e.preventDefault(),e.stopPropagation(),!this.is_disabled)return this.choice_destroy(t(e.target))},n.prototype.choice_destroy=function(t){if(this.result_deselect(t[0].getAttribute("data-option-array-index")))return this.active_field?this.search_field.focus():this.show_search_field_default(),this.is_multiple&&this.choices_count()>0&&this.get_search_field_value().length<1&&this.results_hide(),t.parents("li").first().remove(),this.search_field_scale()},n.prototype.results_reset=function(){if(this.reset_single_select_options(),this.form_field.options[0].selected=!0,this.single_set_selected_text(),this.show_search_field_default(),this.results_reset_cleanup(),this.trigger_form_field_change(),this.active_field)return this.results_hide()},n.prototype.results_reset_cleanup=function(){return this.current_selectedIndex=this.form_field.selectedIndex,this.selected_item.find("abbr").remove()},n.prototype.result_select=function(t){var e,s;if(this.result_highlight)return e=this.result_highlight,this.result_clear_highlight(),this.is_multiple&&this.max_selected_options<=this.choices_count()?(this.form_field_jq.trigger("chosen:maxselected",{chosen:this}),!1):(this.is_multiple?e.removeClass("active-result"):this.reset_single_select_options(),e.addClass("result-selected"),s=this.results_data[e[0].getAttribute("data-option-array-index")],s.selected=!0,this.form_field.options[s.options_index].selected=!0,this.selected_option_count=null,this.search_field.val(""),this.is_multiple?this.choice_build(s):this.single_set_selected_text(this.choice_label(s)),this.is_multiple&&(!this.hide_results_on_select||t.metaKey||t.ctrlKey)?this.winnow_results():(this.results_hide(),this.show_search_field_default()),(this.is_multiple||this.form_field.selectedIndex!==this.current_selectedIndex)&&this.trigger_form_field_change({selected:this.form_field.options[s.options_index].value}),this.current_selectedIndex=this.form_field.selectedIndex,t.preventDefault(),this.search_field_scale())},n.prototype.single_set_selected_text=function(t){return null==t&&(t=this.default_text),t===this.default_text?this.selected_item.addClass("chosen-default"):(this.single_deselect_control_build(),this.selected_item.removeClass("chosen-default")),this.selected_item.find("span").html(t)},n.prototype.result_deselect=function(t){var e;return e=this.results_data[t],!this.form_field.options[e.options_index].disabled&&(e.selected=!1,this.form_field.options[e.options_index].selected=!1,this.selected_option_count=null,this.result_clear_highlight(),this.results_showing&&this.winnow_results(),this.trigger_form_field_change({deselected:this.form_field.options[e.options_index].value}),this.search_field_scale(),!0)},n.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect)return this.selected_item.find("abbr").length||this.selected_item.find("span").first().after(' '),this.selected_item.addClass("chosen-single-with-deselect")},n.prototype.get_search_field_value=function(){return this.search_field.val()},n.prototype.get_search_text=function(){return t.trim(this.get_search_field_value())},n.prototype.escape_html=function(e){return t("
").text(e).html()},n.prototype.winnow_results_set_highlight=function(){var t,e;if(e=this.is_multiple?[]:this.search_results.find(".result-selected.active-result"),null!=(t=e.length?e.first():this.search_results.find(".active-result").first()))return this.result_do_highlight(t)},n.prototype.no_results=function(t){var e;return e=this.get_no_results_html(t),this.search_results.append(e),this.form_field_jq.trigger("chosen:no_results",{chosen:this})},n.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},n.prototype.keydown_arrow=function(){var t;return this.results_showing&&this.result_highlight?(t=this.result_highlight.nextAll("li.active-result").first())?this.result_do_highlight(t):void 0:this.results_show()},n.prototype.keyup_arrow=function(){var t;return this.results_showing||this.is_multiple?this.result_highlight?(t=this.result_highlight.prevAll("li.active-result")).length?this.result_do_highlight(t.first()):(this.choices_count()>0&&this.results_hide(),this.result_clear_highlight()):void 0:this.results_show()},n.prototype.keydown_backstroke=function(){var t;return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(t=this.search_container.siblings("li.search-choice").last()).length&&!t.hasClass("search-choice-disabled")?(this.pending_backstroke=t,this.single_backstroke_delete?this.keydown_backstroke():this.pending_backstroke.addClass("search-choice-focus")):void 0},n.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},n.prototype.search_field_scale=function(){var e,s,i,n,r,o,h;if(this.is_multiple){for(r={position:"absolute",left:"-1000px",top:"-1000px",display:"none",whiteSpace:"pre"},s=0,i=(o=["fontSize","fontStyle","fontWeight","fontFamily","lineHeight","textTransform","letterSpacing"]).length;s ").css(r)).text(this.get_search_field_value()),t("body").append(e),h=e.width()+25,e.remove(),this.container.is(":visible")&&(h=Math.min(this.container.outerWidth()-10,h)),this.search_field.width(h)}},n.prototype.trigger_form_field_change=function(t){return this.form_field_jq.trigger("input",t),this.form_field_jq.trigger("change",t)},n}()}).call(this);
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/sortable.js b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/sortable.js
new file mode 100644
index 00000000..99f12b92
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/js/sortable.js
@@ -0,0 +1,1059 @@
+(function($) {
+ var START_EVENT = 'mousedown touchstart MSPointerDown pointerdown'
+ , END_EVENT = 'mouseup touchend MSPointerUp pointerup'
+ , MOVE_EVENT = 'mousemove touchmove MSPointerMove pointermove scroll'
+
+ function translate(el, x, y) {
+ vendorify('transform', el, 'translate(' + x + 'px, ' + y + 'px)')
+ }
+
+ function transition(el, val) {
+ vendorify('transition', el, val)
+ }
+
+ function getTouchPageX(e) {
+ e = e.originalEvent || e
+ return window.event && window.event.changedTouches && event.changedTouches[0].pageX || e.pageX
+ }
+
+ function getTouchPageY(e) {
+ e = e.originalEvent || e
+ return window.event && window.event.changedTouches && event.changedTouches[0].pageY || e.pageY
+ }
+
+ function vendorify(property, el, val) {
+ property = property.toLowerCase()
+ var titleCased = property.charAt(0).toUpperCase() + property.substr(1)
+ var vendorPrefixes = ['webkit', 'Moz', 'ms', 'O']
+ var properties = vendorPrefixes.map(function(prefix) {
+ return prefix + titleCased
+ }).concat('transform')
+ for (var i = 0, len = properties.length; i < len; ++i) {
+ if (properties[i] in el.style) {
+ if (val !== undefined) el.style[properties[i]] = val
+ else return el.style[properties[i]]
+ break
+ }
+ }
+ }
+
+ var eventProperties = [
+ 'altKey', 'bubbles', 'button', 'cancelable', 'charCode', 'clientX',
+ 'clientY', 'ctrlKey', 'currentTarget', 'data', 'detail', 'eventPhase',
+ 'metaKey', 'offsetX', 'offsetY', 'originalTarget', 'pageX', 'pageY',
+ 'relatedTarget', 'screenX', 'screenY', 'shiftKey', 'target', 'view',
+ 'which'
+ ]
+ function trigger(el, name, originalEvent, arg) {
+ if (!el[0]) return
+
+ originalEvent = originalEvent.originalEvent || originalEvent
+ var props = {}
+ eventProperties.forEach(function(prop) {
+ props[prop] = originalEvent[prop]
+ })
+ props.currentTarget = props.target = el[0]
+
+ var win = (el[0].ownerDocument.defaultView || el[0].ownerDocument.parentWindow)
+ var $ = win.Zepto || win.jQuery
+
+ var e = $.Event(name, props)
+ $(el[0]).trigger(e, arg)
+ return e
+ }
+
+ var nextId = 0
+ var Dragging = function() {
+ this.eventHandler = $('
')
+ this.parent = this.el = this.handle = null
+ this.origin = { x: 0, y: 0, transition: null, translate: null, offset: { x: 0, y: 0 } }
+ this.lastEntered = this.currentTarget = null
+ this.lastX = this.lastY = this.lastDirection = null
+ this.originalCss = {}
+ this.windows = [window]
+
+ var placeholder
+ Object.defineProperty(this, 'placeholder', {
+ get: function() { return placeholder },
+ set: function(val) {
+ if (placeholder === val) return
+ if (placeholder) placeholder.remove()
+ placeholder = val
+ }
+ })
+ }
+
+ Dragging.prototype.on = function() {
+ this.eventHandler.on.apply(this.eventHandler, Array.prototype.slice.call(arguments))
+ return this
+ }
+
+ Dragging.prototype.off = function() {
+ this.eventHandler.off.apply(this.eventHandler, Array.prototype.slice.call(arguments))
+ return this
+ }
+
+ Dragging.prototype.start = function(parent, el, e, handle) {
+ this.parent = parent
+ this.el = el
+ this.handle = handle
+ var el = this.handle || this.el
+ this.origin.x = getTouchPageX(e)
+ this.origin.y = getTouchPageY(e)
+ this.origin.transform = vendorify('transform', this.el[0])
+ this.origin.transition = vendorify('transition', this.el[0])
+ var rect = this.el[0].getBoundingClientRect()
+ this.origin.offset.x = rect.left + (window.scrollX || window.pageXOffset) - this.origin.x
+ this.origin.offset.y = rect.top + (window.scrollY || window.pageYOffset) - this.origin.y
+ this.origin.scrollX = (window.scrollX || window.pageXOffset)
+ this.origin.scrollY = (window.scrollY || window.pageYOffset)
+ // the draged element is going to stick right under the cursor
+ // setting the css property `pointer-events` to `none` will let
+ // the pointer events fire on the elements underneath the helper
+ el[0].style.pointerEvents = 'none'
+ this.windows.forEach(function(win) {
+ $(win).on(MOVE_EVENT, $.proxy(this.move, this))
+ $(win).on(END_EVENT, $.proxy(this.stop, this))
+ }, this)
+ transition(el[0], '')
+ trigger(this.eventHandler, 'dragging:start', e)
+ return this.el
+ }
+
+ Dragging.prototype.stop = function(e) {
+ var dropEvent = null
+ var revert = true
+ if (this.last) {
+ var last = this.last
+ this.last = null
+ dropEvent = trigger($(last), 'dragging:drop', e)
+ revert = !dropEvent.isDefaultPrevented()
+ }
+
+ if (!this.el) {
+ return
+ }
+
+ for (var prop in this.originalCss) {
+ this.el.css(prop, this.originalCss[prop])
+ delete this.originalCss[prop]
+ }
+
+ trigger(this.eventHandler, 'dragging:stop', e, this.el)
+ this.placeholder = null
+ if (!this.handle) {
+ this.adjustPlacement(e)
+ }
+
+ var el = this.el
+ if (this.handle) {
+ this.handle.remove()
+ }
+
+ setTimeout((function(el, origin) {
+ transition(el[0], 'all 0.25s ease-in-out 0s')
+ vendorify('transform', el[0], origin.transform || '')
+ setTimeout(transition.bind(null, el[0], origin.transition || ''), 250)
+ el[0].style.pointerEvents = ''
+ }).bind(null, el, this.origin))
+
+ this.windows.forEach(function(win) {
+ $(win).off(MOVE_EVENT, this.move)
+ $(win).off(END_EVENT, this.stop)
+ }, this)
+ this.parent = this.el = this.handle = null
+ }
+
+ Dragging.prototype.move = function(e) {
+ if (!this.el) return
+
+ var doc = this.el[0].ownerDocument
+ var win = doc.defaultView || doc.parentWindow
+
+ if (e.type !== 'scroll') {
+ var pageX = getTouchPageX(e)
+ var pageY = getTouchPageY(e)
+
+ if (e.view !== win && e.view.frameElement) {
+ pageX += e.view.frameElement.offsetLeft
+ pageY += e.view.frameElement.offsetTop
+ }
+
+ var clientX = e.clientX || (e.originalEvent && e.originalEvent.clientX) || window.event && window.event.touches && window.event.touches[0].clientX || 0
+ , clientY = e.clientY || (e.originalEvent && e.originalEvent.clientY) || window.event && window.event.touches && window.event.touches[0].clientY || 0
+
+ var doc = this.el[0].ownerDocument
+ var over
+ if (!isOldIE) {
+ over = e.view.document.elementFromPoint(clientX, clientY)
+ } else {
+ over = e.view.document.msElementsFromPoint(clientX, clientY)
+ over = over[0] === this.el[0] ? over[1] : over[0]
+ }
+
+ var deltaX = this.lastX - pageX
+ var deltaY = this.lastY - pageY
+ var direction = deltaY > 0 && 'up' || deltaY < 0 && 'down'
+ || deltaX > 0 && 'up'|| deltaX < 0 && 'down'
+ || this.lastDirection
+ if (!dragging.currentTarget) {
+ this.setCurrent(over)
+ }
+
+ if (this.currentTarget) {
+ if (over !== this.last && this.lastEntered !== this.currentTarget) {
+ trigger($(this.lastEntered), 'dragging:leave', e)
+ trigger($(this.currentTarget), 'dragging:enter', e)
+ this.lastEntered = this.currentTarget
+ } else if (direction !== this.lastDirection) {
+ trigger($(this.currentTarget), 'dragging:diverted', e)
+ }
+ }
+
+ this.last = over
+ this.currentTarget = null
+ this.lastDirection = direction
+ this.lastX = pageX
+ this.lastY = pageY
+ this.origin.scrollX = (window.scrollX || window.pageXOffset)
+ this.origin.scrollY = (window.scrollY || window.pageYOffset)
+ } else {
+ var pageX = this.lastX + ((window.scrollX || window.pageXOffset) - this.origin.scrollX)
+ , pageY = this.lastY + ((window.scrollY || window.pageYOffset) - this.origin.scrollY)
+ }
+
+ // border scrolling only for root window
+ if (e.view !== win && e.view && e.view.frameElement) {
+ var bottom = (pageY - (window.scrollY || window.pageYOffset) - window.innerHeight) * -1
+ var bottomReached = document.documentElement.offsetHeight < (window.scrollY || window.pageYOffset) + window.innerHeight
+ if (bottom <= 10 && !bottomReached) {
+ setTimeout(function() { window.scrollBy(0, 5) }, 50)
+ }
+
+ var top = (pageY - (window.scrollY || window.pageYOffset))
+ var topReached = (window.scrollY || window.pageYOffset) <= 0
+ if (top <= 10 && !topReached) {
+ setTimeout(function() { window.scrollBy(0, -5) }, 50)
+ }
+ }
+
+ var deltaX = pageX - this.origin.x
+ , deltaY = pageY - this.origin.y
+ var el = this.handle || this.el
+
+ translate(el[0], deltaX, deltaY)
+ }
+
+ Dragging.prototype.setCurrent = function(target) {
+ this.currentTarget = target
+ }
+
+ Dragging.prototype.css = function(prop, val) {
+ if (!this.el) return
+ this.originalCss[prop] = this.el.css(prop)
+ this.el.css(prop, val)
+ }
+
+ Dragging.prototype.adjustPlacement = function(e) {
+ var el = this.handle && this.handle[0] || this.el[0]
+ translate(el, 0, 0)
+ var rect = el.getBoundingClientRect()
+ this.origin.x = rect.left + (window.scrollX || window.pageXOffset) - this.origin.offset.x
+ this.origin.y = rect.top + (window.scrollY || window.pageYOffset) - this.origin.offset.y
+ var pageX = getTouchPageX(e) || this.lastX
+ , pageY = getTouchPageY(e) || this.lastY
+ , deltaX = pageX - this.origin.x
+ , deltaY = pageY - this.origin.y
+ translate(el, deltaX, deltaY)
+ }
+
+ var dragging
+ try {
+ if (parent.$ && parent.$.dragging) {
+ dragging = parent.$.dragging
+ dragging.windows.push(window)
+ }
+ } catch (e) {}
+
+ dragging = $.dragging = dragging || new Dragging()
+
+ // from https://github.com/rkusa/selector-observer
+ var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
+ function matches(el, selector) {
+ var fn = el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector
+ return fn ? fn.call(el, selector) : false
+ }
+ function toArr(nodeList) {
+ return Array.prototype.slice.call(nodeList)
+ }
+
+ // polyfill for IE < 11
+ var isOldIE = false
+ if (typeof MutationObserver === 'undefined') {
+ MutationObserver = function(callback) {
+ this.targets = []
+ this.onAdded = function(e) {
+ callback([{ addedNodes: [e.target], removedNodes: [] }])
+ }
+ this.onRemoved = function(e) {
+ callback([{ addedNodes: [], removedNodes: [e.target] }])
+ }
+ }
+
+ MutationObserver.prototype.observe = function(target) {
+ target.addEventListener('DOMNodeInserted', this.onAdded)
+ target.addEventListener('DOMNodeRemoved', this.onRemoved)
+ this.targets.push(target)
+ }
+
+ MutationObserver.prototype.disconnect = function() {
+ var target
+ while (target = this.targets.shift()) {
+ target.removeEventListener('DOMNodeInserted', this.onAdded)
+ target.removeEventListener('DOMNodeRemoved', this.onRemoved)
+ }
+ }
+
+ isOldIE = !!~navigator.appName.indexOf('Internet Explorer')
+ }
+
+ var SelectorObserver = function(targets, selector, onAdded, onRemoved) {
+ var self = this
+ this.targets = targets instanceof NodeList
+ ? Array.prototype.slice.call(targets)
+ : [targets]
+
+ // support selectors starting with the childs only selector `>`
+ var childsOnly = selector[0] === '>'
+ var search = childsOnly ? selector.substr(1) : selector
+ var initialized = false
+
+ function query(nodes, deep) {
+ var result = []
+
+ toArr(nodes).forEach(function(node) {
+ //ignore non-element nodes
+ if (node.nodeType !== 1) return;
+
+ // if looking for childs only, the node's parentNode
+ // should be one of our targets
+ if (childsOnly && self.targets.indexOf(node.parentNode) === -1) {
+ return
+ }
+
+ // test if the node itself matches the selector
+ if (matches(node, search)) {
+ result.push(node)
+ }
+
+ if (childsOnly || !deep) {
+ return
+ }
+
+ toArr(node.querySelectorAll(selector)).forEach(function(node) {
+ result.push(node)
+ })
+ })
+
+ return result
+ }
+
+ function apply(nodes, deep, callback) {
+ if (!callback) {
+ return
+ }
+
+ // flatten
+ query(nodes, deep)
+ // filter unique nodes
+ .filter(function(node, i, self) {
+ return self.indexOf(node) === i
+ })
+ // execute callback
+ .forEach(function(node) {
+ callback.call(node)
+ })
+ }
+
+ var timeout = null
+ var addedNodes = []
+ var removedNodes = []
+
+ function handle() {
+ self.disconnect()
+
+ // filter moved elements (removed and re-added)
+ for (var i = 0, len = removedNodes.length; i < len; ++i) {
+ var index = addedNodes.indexOf(removedNodes[i])
+ if (index > -1) {
+ addedNodes.splice(index, 1)
+ removedNodes.splice(i--, 1)
+ }
+ }
+
+ // ↓ IE workarounds ...
+ apply(addedNodes, !(initialized && isOldIE), onAdded)
+ apply(removedNodes, true, onRemoved)
+
+ addedNodes.length = 0
+ removedNodes.length = 0
+
+ self.observe()
+ }
+
+ this.observer = new MutationObserver(function(mutations) {
+ mutations.forEach(function(mutation) {
+ addedNodes.push.apply(addedNodes, mutation.addedNodes)
+ removedNodes.push.apply(removedNodes, mutation.removedNodes)
+ })
+
+ // IE < 10 fix: wait a cycle to gather all mutations
+ if (timeout) {
+ clearTimeout(timeout)
+ }
+ timeout = setTimeout(handle)
+ })
+
+ // call onAdded for existing elements
+ if (onAdded) {
+ this.targets.forEach(function(target) {
+ apply(target.children, true, onAdded)
+ })
+ }
+
+ initialized = true
+
+ this.observe()
+ }
+
+ SelectorObserver.prototype.disconnect = function() {
+ this.observer.disconnect()
+ }
+
+ SelectorObserver.prototype.observe = function() {
+ var self = this
+ this.targets.forEach(function(target) {
+ self.observer.observe(target, { childList: true, subtree: true })
+ })
+ }
+
+ var Draggable = function(element, opts) {
+ this.id = nextId++
+ this.el = $(element)
+ this.opts = opts
+ this.cancel = opts.handle !== false
+ }
+
+ Draggable.prototype.create = function() {
+ this.el
+ .on(START_EVENT, $.proxy(this.start, this))
+ .css('touch-action', 'double-tap-zoom')
+ .css('-ms-touch-action', 'double-tap-zoom')
+
+ dragging.on('dragging:stop', $.proxy(this.reset, this))
+
+ var self = this
+ setTimeout(function() {
+ self.el.trigger('draggable:create', self)
+ })
+ }
+
+ Draggable.prototype.destroy = function() {
+ this.el.off(START_EVENT, this.start)
+
+ // Todo: Fix Zepto Bug
+ dragging.off('dragging:stop', this.reset)
+ }
+
+ Draggable.prototype.enable = function() {
+ this.opts.disabled = false
+ }
+
+ Draggable.prototype.disable = function() {
+ this.opts.disabled = true
+ }
+
+ Draggable.prototype.start = function(e) {
+ if (this.opts.disabled) {
+ return false
+ }
+
+ // only start on left mouse button
+ if (e.type === 'mousedown' && e.which !== 1) {
+ return false
+ }
+
+ e = e.originalEvent || e // zepto <> jquery compatibility
+
+ if (this.opts.cancel) {
+ var target = $(e.target)
+ while (target[0] !== this.el[0]) {
+ if (target.is(this.opts.cancel)) return
+ target = target.parent()
+ }
+ }
+
+ if (this.opts.handle) {
+ var target = $(e.target), isHandle = false
+ while (target[0] !== this.el[0]) {
+ if (target.is(this.opts.handle)) {
+ isHandle = true
+ break
+ }
+ target = target.parent()
+ }
+ if (!isHandle) return
+ }
+
+ // prevent text selection
+ e.preventDefault()
+
+ var el = this.el, helper
+ if (this.opts.clone) {
+ if (typeof this.opts.clone === 'function') {
+ helper = this.opts.clone.call(this.el)
+ } else {
+ helper = this.el.clone()
+ if (this.opts.cloneClass) {
+ helper.addClass(this.opts.cloneClass)
+ }
+ }
+ var position = this.el.position()
+ helper.css('position', 'absolute')
+ .css('left', position.left).css('top', position.top)
+ .width(this.el.width()).height(this.el.height())
+ helper.insertAfter(this.el)
+ }
+
+ dragging.start(this, this.el, e, helper)
+
+ trigger(this.el, 'draggable:start', e, { item: dragging.el })
+ }
+
+ Draggable.prototype.reset = function(e, last) {
+ if (last === this.el[0]) {
+ trigger(this.el, 'draggable:stop', e, { item: dragging.el })
+ }
+ }
+
+ var Droppable = function(element, opts) {
+ this.id = nextId++
+ this.el = $(element)
+ this.opts = opts
+ this.accept = false
+ }
+
+ Droppable.prototype.create = function() {
+ this.el
+ .on('dragging:enter', $.proxy(this.enter, this))
+ .on('dragging:leave', $.proxy(this.leave, this))
+ .on('dragging:drop', $.proxy(this.drop, this))
+
+ dragging
+ .on('dragging:start', $.proxy(this.activate, this))
+ .on('dragging:stop', $.proxy(this.reset, this))
+
+ var self = this
+ setTimeout(function() {
+ self.el.trigger('droppable:create', self)
+ })
+ }
+
+ Droppable.prototype.destroy = function() {
+ this.el
+ .off('dragging:enter', this.enter)
+ .off('dragging:leave', this.leave)
+ .off('dragging:drop', this.drop)
+
+ // Todo: Fix Zepto Bug
+ // dragging
+ // .off('dragging:start', this.activate)
+ // .off('dragging:stop', this.reset)
+ }
+
+ Droppable.prototype.enable = function() {
+ this.opts.disabled = false
+ }
+
+ Droppable.prototype.disable = function() {
+ this.opts.disabled = true
+ }
+
+ Droppable.prototype.activate = function(e) {
+ this.accept = dragging.parent.opts.connectWith && this.el.is(dragging.parent.opts.connectWith)
+
+ if (!this.accept) {
+ var accept = this.opts.accept === '*'
+ || (typeof this.opts.accept === 'function' ? this.opts.accept.call(this.el[0], dragging.el)
+ : dragging.el.is(this.opts.accept))
+ if (this.opts.scope !== 'default') {
+ this.accept = dragging.parent.opts.scope === this.opts.scope
+ if (!this.accept && this.opts.accept !== '*') this.accept = accept
+ } else this.accept = accept
+ }
+
+ if (!this.accept) return
+ if (this.opts.activeClass)
+ this.el.addClass(this.opts.activeClass)
+
+ trigger(this.el, 'droppable:activate', e, { item: dragging.el })
+ }
+
+ Droppable.prototype.reset = function(e) {
+ if (!this.accept) return
+ if (this.opts.activeClass) this.el.removeClass(this.opts.activeClass)
+ if (this.opts.hoverClass) this.el.removeClass(this.opts.hoverClass)
+
+ trigger(this.el, 'droppable:deactivate', e, { item: dragging.el })
+ }
+
+ Droppable.prototype.enter = function(e) {
+ if (this.opts.disabled) return false
+
+ e.stopPropagation()
+
+ // hide placeholder, if set (e.g. enter the droppable after
+ // entering a sortable)
+ if (dragging.placeholder) dragging.placeholder.hide()
+
+ if (!this.accept) return
+
+ if (this.opts.hoverClass) {
+ this.el.addClass(this.opts.hoverClass)
+ }
+
+ trigger(this.el, 'droppable:over', e, { item: dragging.el })
+ }
+
+ Droppable.prototype.leave = function(e) {
+ if (this.opts.disabled) return false
+ // e.stopPropagation()
+
+ if (this.opts.hoverClass && this.accept) {
+ this.el.removeClass(this.opts.hoverClass)
+ }
+
+ trigger(this.el, 'droppable:out', e, { item: dragging.el })
+ }
+
+ Droppable.prototype.drop = function(e) {
+ if (this.opts.disabled || !this.accept) return false
+
+ if (!dragging.el) return
+
+ var el = dragging.el
+ var handler = typeof this.opts.receiveHandler === 'function' && this.opts.receiveHandler
+ var evtObj = { item: el }
+ var clone = null
+ if (dragging.handle) {
+ evtObj.helper = dragging.handle
+ if (!handler) {
+ clone = evtObj.clone = dragging.el.clone()
+ }
+ }
+
+ var drop = trigger(this.el, 'droppable:drop', e, evtObj)
+
+ if (!drop.isDefaultPrevented()) {
+ if (handler) {
+ handler.call(this.el, evtObj)
+ } else {
+ $(this.el).append(clone || dragging.el)
+ }
+ }
+ }
+
+ var Sortable = function(element, opts) {
+ this.id = nextId++
+ this.el = element
+ this.opts = opts
+
+ var tag = this.opts.placeholderTag
+ if (!tag) {
+ try {
+ tag = this.el.find(this.opts.items)[0].tagName
+ } catch(e) {
+ tag = /^ul|ol$/i.test(this.el[0].tagName) ? 'li' : 'div'
+ }
+ }
+
+ this.placeholder = $('<' + tag + ' id="__ph' + this.id + '" class="' + this.opts.placeholder + '" />')
+
+ this.accept = this.index = this.direction = null
+ }
+
+ Sortable.prototype.create = function() {
+ this.el
+ .on(START_EVENT, this.opts.items, $.proxy(this.start, this))
+ .on('dragging:enter', this.opts.items, $.proxy(this.enter, this))
+ .on('dragging:diverted', this.opts.items, $.proxy(this.diverted, this))
+ .on('dragging:drop', this.opts.items, $.proxy(this.drop, this))
+
+ $(this.el).find(this.opts.items)
+ .css('touch-action', 'double-tap-zoom')
+ .css('-ms-touch-action', 'double-tap-zoom')
+
+ this.el
+ .on('dragging:enter', $.proxy(this.enter, this))
+ .on('dragging:diverted', $.proxy(this.diverted, this))
+ .on('dragging:drop', $.proxy(this.drop, this))
+
+ dragging
+ .on('dragging:start', $.proxy(this.activate, this))
+ .on('dragging:stop', $.proxy(this.reset, this))
+
+ var self = this
+ setTimeout(function() {
+ self.el.trigger('sortable:create', self)
+ })
+
+ this.observer = new SelectorObserver(this.el[0], this.opts.items, function() {
+ }, function() {
+ if (this === self.placeholder[0] || (dragging.el && this === dragging.el[0])) {
+ return
+ }
+ var item = $(this)
+ item.css('touch-action', 'double-tap-zoom')
+ .css('-ms-touch-action', 'double-tap-zoom')
+ self.el.trigger('sortable:change', { item: item })
+ self.el.trigger('sortable:update', { item: item, index: -1 })
+ })
+ }
+
+ Sortable.prototype.destroy = function() {
+ this.el
+ .off(START_EVENT, this.opts.items, this.start)
+ .off('dragging:enter', this.opts.items, this.enter)
+ .off('dragging:diverted', this.opts.items, this.diverted)
+ .off('dragging:drop', this.opts.items, this.drop)
+
+ this.el
+ .off('dragging:enter', this.enter)
+ .off('dragging:diverted', this.diverted)
+ .off('dragging:drop', this.drop)
+
+ // Todo: Fix Zepto Bug
+ // dragging
+ // .off('dragging:start', this.activate)
+ // .off('dragging:stop', this.reset)
+
+ this.observer.disconnect()
+ }
+
+ Sortable.prototype.enable = function() {
+ this.opts.disabled = false
+ }
+
+ Sortable.prototype.disable = function() {
+ this.opts.disabled = true
+ }
+
+ Sortable.prototype.activate = function(e) {
+ this.isEmpty = this.el.find(this.opts.items).length === 0
+
+ this.accept = dragging.parent.id === this.id
+
+ if (!this.accept && dragging.parent.opts.connectWith) {
+ this.accept = this.el.is(dragging.parent.opts.connectWith)
+ }
+
+ if (!this.accept) return
+
+ this.accept = dragging.parent.id === this.id
+ || this.opts.accept === '*'
+ || (typeof this.opts.accept === 'function'
+ ? this.opts.accept.call(this.el[0], dragging.el)
+ : dragging.el.is(this.opts.accept))
+
+ if (!this.accept) return
+
+ if (this.opts.activeClass)
+ this.el.addClass(this.opts.activeClass)
+
+ trigger(this.el, 'sortable:activate', e, { item: dragging.el })
+ }
+
+ Sortable.prototype.reset = function(e) {
+ if (!this.accept) return
+ if (this.opts.activeClass) {
+ this.el.removeClass(this.opts.activeClass)
+ }
+
+ trigger(this.el, 'sortable:deactivate', e, { item: dragging.el })
+
+ if (this.index !== null) {
+ trigger(this.el, 'sortable:beforeStop', e, { item: dragging.el })
+ trigger(this.el, 'sortable:stop', e, { item: dragging.el })
+ this.index = null
+ }
+ }
+
+ Sortable.prototype.indexOf = function(el) {
+ return this.el.find(this.opts.items + ', #' + this.placeholder.attr('id')).index(el)
+ }
+
+ Sortable.prototype.start = function(e) {
+ if (this.opts.disabled || dragging.el) {
+ return
+ }
+
+ // only start on left mouse button
+ if (e.type === 'mousedown' && e.which !== 1) {
+ return false
+ }
+
+ if (this.opts.cancel) {
+ var target = $(e.target)
+ while (target[0] !== this.el[0]) {
+ if (target.is(this.opts.cancel)) return
+ target = target.parent()
+ }
+ }
+
+ if (this.opts.handle) {
+ var target = $(e.target), isHandle = false
+ while (target[0] !== this.el[0]) {
+ if (target.is(this.opts.handle)) {
+ isHandle = true
+ break
+ }
+ target = target.parent()
+ }
+ if (!isHandle) return
+ }
+
+ e.stopPropagation()
+ e.preventDefault() // prevent text selection
+
+ // use e.currentTarget instead of e.target because we want the target
+ // the event is bound to, not the target (child) the event is triggered from
+ dragging.start(this, $(e.currentTarget), e)
+
+ this.index = this.indexOf(dragging.el)
+
+ dragging.el.before(dragging.placeholder = this.placeholder.show())
+
+ // if dragging an item that belongs to the current list, hide it while
+ // it is being dragged
+ if (this.index !== null) {
+ // zepto <> jquery compatibility
+ var height = dragging.el.outerHeight ? dragging.el.outerHeight() : dragging.el.height()
+ dragging.css('margin-bottom', -height)
+ }
+
+ if (this.opts.forcePlaceholderSize) {
+ this.placeholder.height(parseFloat(dragging.el.css('height')))
+ this.placeholder.width(parseFloat(dragging.el.css('width')))
+ }
+
+ dragging.adjustPlacement(e)
+
+ trigger(this.el, 'sortable:start', e, { item: dragging.el })
+ }
+
+ Sortable.prototype.enter = function(e) {
+ if (!this.accept || this.opts.disabled) return
+
+ e.stopPropagation()
+
+ // stop if event is fired on the placeholder
+ var child = e.currentTarget, isContainer = child === this.el[0]
+ if (child === this.placeholder[0]) return
+ child = $(child)
+
+ // the container fallback is only necessary for empty sortables
+ if (isContainer && !this.isEmpty && this.placeholder.parent().length) {
+ return
+ }
+
+ dragging.placeholder = this.placeholder
+
+ if (this.opts.forcePlaceholderSize) {
+ this.placeholder.height(parseFloat(dragging.el.css('height')))
+ this.placeholder.width(parseFloat(dragging.el.css('width')))
+ }
+
+ if (!isContainer) {
+ this.diverted(e)
+ } else {
+ this.el.append(this.placeholder)
+ this.el.trigger('sortable:change', { item: dragging.el })
+ }
+ }
+
+ Sortable.prototype.diverted = function(e) {
+ if (!this.accept || this.opts.disabled) return
+ e.stopPropagation()
+
+ var child = $(e.currentTarget), isContainer = child[0] === this.el[0]
+ if (isContainer) return
+
+ // insert the placeholder according to the dragging direction
+ dragging.placeholder = this.placeholder
+ this.direction = this.indexOf(this.placeholder.show()) < this.indexOf(child) ? 'down' : 'up'
+ child[this.direction === 'down' ? 'after' : 'before'](this.placeholder)
+ dragging.adjustPlacement(e)
+
+ this.el.trigger('sortable:change', { item: dragging.el })
+ }
+
+ Sortable.prototype.drop = function(e) {
+ if (!this.accept || this.opts.disabled) return
+
+ e.stopPropagation()
+ e.preventDefault()
+
+ if (!dragging.el) return
+ if (!this.placeholder.parent().length) return
+
+ trigger(this.el, 'sortable:beforeStop', e, { item: dragging.el })
+
+ this.observer.disconnect()
+
+ var newIndex = this.indexOf(this.placeholder)
+ if (newIndex > this.index) {
+ newIndex--
+ }
+
+ var handler
+
+ // dropped element belongs to another list
+ if (this.index === null) {
+ handler = this.opts.receiveHandler
+ }
+ // dopped element belongs to the same list
+ else {
+ // updatePosition cause backwards-compatibility
+ handler = this.opts.updateHandler || this.opts.updatePosition
+ }
+
+ var el = dragging.el
+ if (typeof handler === 'function') {
+ handler.call(this.el, { item: dragging.el, index: newIndex })
+ } else {
+ if (dragging.handle) {
+ el = dragging.el.clone()
+ }
+ el.insertBefore(this.placeholder)
+ }
+
+ // if the dropped element belongs to another list, trigger the receive event
+ if (this.index === null) {
+ trigger(this.el, 'sortable:receive', e, { item: el })
+ }
+
+ // if the index changed, trigger the update event
+ if (newIndex !== this.index) {
+ this.el.trigger('sortable:update', { item: el, index: newIndex })
+ }
+
+ trigger(this.el, 'sortable:stop', e, { item: el })
+ this.index = null
+ this.observer.observe()
+
+ dragging.stop(e)
+ }
+
+ Sortable.prototype.toArray = function(opts) {
+ if (!opts) opts = {}
+ var attr = opts.attribute || 'id', attrs = []
+ this.el.find(this.opts.items).each(function() {
+ if ($(this).attr(attr)) {
+ attrs.push($(this).attr(attr))
+ }
+ })
+ return attrs
+ }
+
+ function generic(constructor, identifier, defaults) {
+ return function(opts, name, value) {
+ var result = []
+ this.each(function() {
+ var instance = $(this).data(identifier)
+ if (typeof opts === 'string') {
+ if (typeof instance === 'undefined')
+ throw new Error(identifier + ' not defined')
+ switch (opts) {
+ case 'enable': instance.enable(); break
+ case 'disable': instance.disable(); break
+ case 'destroy':
+ instance.destroy()
+ $(this).removeData(identifier)
+ break
+ case 'option':
+ // set
+ if (value !== undefined)
+ instance.opts[name] = value
+ else if (typeof name === 'object')
+ instance.opts = $.extend(instance.opts, name)
+ // get
+ else if (name)
+ result.push(instance.opts[name])
+ else
+ result.push(instance.opts)
+ break
+ // case 'serialize':
+ // if (identifier !== 'sortable') return
+ // result.push(instance.serialize())
+ // break
+ case 'toArray':
+ if (identifier !== 'sortable') return
+ result.push(instance.toArray(name))
+ break
+ }
+ } else {
+ if (instance) {
+ $.extend(instance.opts, opts) // merge options
+ return this
+ }
+ instance = new constructor($(this), $.extend({}, defaults, opts))
+ instance.create()
+ $(this).data(identifier, instance)
+ }
+ })
+
+ if (result.length)
+ return result.length === 1 ? result[0] : result
+ else
+ return this
+ }
+ }
+
+ $.fn.draggable = generic(Draggable, 'draggable', {
+ cancel: 'input, textarea, button, select, option',
+ connectWith: false,
+ cursor: 'auto',
+ disabled: false,
+ handle: false,
+ initialized: false,
+ clone: false,
+ cloneClass: '',
+ scope: 'default'
+ })
+
+ $.fn.droppable = generic(Droppable, 'droppable', {
+ accept: '*',
+ activeClass: '',
+ disabled: false,
+ hoverClass: '',
+ initialized: false,
+ scope: 'default',
+ receiveHandler: null
+ })
+
+ $.fn.sortable = generic(Sortable, 'sortable', {
+ accept: '*',
+ activeClass: '',
+ cancel: 'input, textarea, button, select, option',
+ connectWith: false,
+ disabled: false,
+ forcePlaceholderSize: false,
+ handle: false,
+ initialized: false,
+ items: 'li, div',
+ placeholder: 'placeholder',
+ placeholderTag: null,
+ updateHandler: null,
+ receiveHandler: null
+ })
+})(window.Zepto || window.jQuery);
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/menu.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/menu.php
new file mode 100644
index 00000000..672bc71f
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/menu.php
@@ -0,0 +1,53 @@
+
+
+
+ menu as $item) { ?>
+ view, $item['submenu'])) {
+ $classes[] = 'active';
+ }
+ } else {
+ if ($this->view == $item['view']) {
+ $classes[] = 'active';
+ }
+ } ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/submenu.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/submenu.php
new file mode 100644
index 00000000..92207392
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/submenu.php
@@ -0,0 +1,59 @@
+ array('permission' => 'create', 'icon' => 'fas fa-plus-circle', 'class' => 'green'),
+ 'copy' => array('permission' => 'create', 'icon' => 'far fa-copy', 'class' => 'select'),
+ 'refresh' => array('permission' => 'edit', 'icon' => 'fas fa-sync', 'class' => 'select'),
+ 'edit' => array('permission' => 'view', 'icon' => 'fas fa-edit', 'class' => 'select'),
+ 'publish' => array('permission' => 'state', 'icon' => 'far fa-check-circle', 'class' => 'select'),
+ 'unpublish' => array('permission' => 'state', 'icon' => 'far fa-times-circle', 'class' => 'select'),
+ 'delete' => array('permission' => 'delete', 'icon' => 'fas fa-times', 'class' => 'brown select'),
+ 'empty' => array('permission' => 'delete', 'icon' => 'fas fa-trash-alt', 'class' => 'red'),
+ 'scan' => array('permission' => 'edit', 'icon' => 'fas fa-sync', 'class' => ''),
+ 'save' => array('permission' => 'edit', 'icon' => 'fas fa-save', 'class' => 'green'),
+ 'apply' => array('permission' => 'edit', 'icon' => 'fas fa-check', 'class' => ''),
+ 'cancel' => array('permission' => '', 'icon' => 'fas fa-ban', 'class' => ''),
+ 'update' => array('permission' => 'options', 'icon' => 'fas fa-save', 'class' => 'green'),
+ 'export' => array('permission' => 'options', 'icon' => 'fas fa-download', 'class' => 'green'),
+ 'resend' => array('permission' => 'options', 'icon' => 'fas fa-envelope', 'class' => ''),
+ 'rates' => array('permission' => 'options', 'icon' => 'fas fa-chart-bar', 'class' => ''),
+ 'renew' => array('permission' => 'options', 'icon' => 'fas fa-sync', 'class' => ''),
+ 'reset' => array('permission' => 'options', 'icon' => 'fas fa-undo', 'class' => 'red'));
+
+if (!empty($this->submenu)) { ?>
+
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/table.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/table.php
new file mode 100644
index 00000000..b984b1e0
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/table.php
@@ -0,0 +1,116 @@
+params->get($this->view.'columns', array());
+
+$actions = array(
+ 'copy' => array('permission' => 'create', 'icon' => 'far fa-copy'),
+ 'edit' => array('permission' => 'view', 'icon' => 'fas fa-pencil-alt', 'class' => 'blue'),
+ 'delete' => array('permission' => 'delete', 'icon' => 'fas fa-times', 'class' => 'red'),
+ 'toggle' => array('permission' => 'state', 'icon' => 'far fa-dot-circle'));
+
+?>
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/index.html b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/item.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/item.php
new file mode 100644
index 00000000..200404d9
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/item.php
@@ -0,0 +1,34 @@
+
+
+
+
+ useractions->get('admin.view')) { ?>
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/items.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/items.php
new file mode 100644
index 00000000..e6b9f53f
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/kui/tmpl/items.php
@@ -0,0 +1,62 @@
+
+
+
+
+ useractions->get('admin.view')) { ?>
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/banned.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/banned.php
new file mode 100644
index 00000000..b07222b4
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/banned.php
@@ -0,0 +1,81 @@
+db = JFactory::getDBO();
+ $this->app = JFactory::getApplication();
+
+ if (empty($config['filter_fields'])) {
+ $config['filter_fields'] = array(
+ 'id', 'b.id',
+ 'shout', 'b.shout_id',
+ 'author_id', 'b.author_id',
+ 'author', 'b.author',
+ 'email', 'u.email',
+ 'ip', 'b.ip',
+ 'added', 'b.added');
+ }
+
+ parent::__construct($config);
+ }
+
+ protected function populateState($ordering = 'id', $direction = 'desc')
+ {
+ $search = $this->getUserStateFromRequest($this->context.'.filter.search', 'filter_search');
+ $this->setState('filter.search', $search);
+
+ $this->setState('list.ordering', $ordering);
+ $this->setState('list.direction', $direction);
+
+ parent::populateState($ordering, $direction);
+
+ $limit = $this->getUserStateFromRequest($this->context.'.list.limit', 'filter_limit', $this->app->getCfg('list_limit'), 'uint');
+ $this->setState('filter.limit', $limit);
+ $this->setState('list.limit', $limit);
+
+ $start = $this->getUserStateFromRequest($this->context.'.limitstart', 'limitstart', 0, 'uint');
+ $this->setState('list.start', $start);
+ }
+
+ protected function getListQuery()
+ {
+ $query = $this->db->getQuery(true);
+
+ $query->select("b.*, u.email");
+ $query->from(SPREFIX."banned AS b");
+ $query->leftJoin("#__users AS u ON u.id = b.author_id");
+
+ $search = $this->getState('filter.search');
+
+ if ($search) {
+ if ((substr($search, 0, 1) == '"') && (substr($search, -1) == '"')) {
+ $search = $this->db->quote($this->db->escape(trim($search, '"'), true), false);
+ } else {
+ $search = $this->db->quote('%'.$this->db->escape(trim($search, '"'), true).'%', false);
+ }
+
+ $query->where('b.author LIKE '.$search.' OR b.author_id LIKE '.$search.' OR b.ip LIKE '.$search.' OR u.email LIKE '.$search);
+ }
+
+ $query->order($this->db->escape($this->getState('list.ordering', 'b.id')).' '.$this->db->escape($this->getState('list.direction', 'DESC')));
+
+ return $query;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/categories.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/categories.php
new file mode 100644
index 00000000..1f939df4
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/categories.php
@@ -0,0 +1,87 @@
+db = JFactory::getDBO();
+ $this->app = JFactory::getApplication();
+
+ if (empty($config['filter_fields'])) {
+ $config['filter_fields'] = array(
+ 'id', 'c.id',
+ 'title', 'c.title',
+ 'shouts', 'shouts',
+ 'added', 'c.added');
+ }
+
+ parent::__construct($config);
+ }
+
+ protected function populateState($ordering = 'added', $direction = 'desc')
+ {
+ $search = $this->getUserStateFromRequest($this->context.'.filter.search', 'filter_search');
+ $this->setState('filter.search', $search);
+
+ $status = $this->getUserStateFromRequest($this->context.'.filter.status', 'filter_status', '', 'string');
+ $this->setState('filter.status', $status);
+
+ $this->setState('list.ordering', $ordering);
+ $this->setState('list.direction', $direction);
+
+ parent::populateState($ordering, $direction);
+
+ $limit = $this->getUserStateFromRequest($this->context.'.list.limit', 'filter_limit', $this->app->getCfg('list_limit'), 'uint');
+ $this->setState('filter.limit', $limit);
+ $this->setState('list.limit', $limit);
+
+ $start = $this->getUserStateFromRequest($this->context.'.limitstart', 'limitstart', 0, 'uint');
+ $this->setState('list.start', $start);
+ }
+
+ protected function getListQuery()
+ {
+ $query = $this->db->getQuery(true);
+
+ $query->select("c.*, (SELECT COUNT(id) FROM ".SPREFIX."shouts WHERE category_id = c.id) AS shouts");
+ $query->from(SPREFIX."categories AS c");
+
+ $search = $this->getState('filter.search');
+
+ if (!empty($search)) {
+ if ((substr($search, 0, 1) == '"') && (substr($search, -1) == '"')) {
+ $search = $this->db->quote($this->db->escape(trim($search, '"'), true), false);
+ $description = "MATCH (c.description) AGAINST (".$search." IN BOOLEAN MODE)";
+ } else {
+ $search = $this->db->quote('%'.$this->db->escape(trim($search, '"'), true).'%', false);
+ $description = "c.description LIKE ".$search;
+ }
+
+ $query->where($description." OR c.title LIKE ".$search);
+ }
+
+ $status = $this->getState('filter.status');
+
+ if (is_numeric($status)) $query->where('c.status = '.(int)$status);
+
+ $query->group('c.id');
+ $query->order($this->db->escape($this->getState('list.ordering', 'c.title')).' '.$this->db->escape($this->getState('list.direction', 'asc')));
+
+ return $query;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/category.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/category.php
new file mode 100644
index 00000000..d47c1cbe
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/category.php
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/home.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/home.php
new file mode 100644
index 00000000..d70f0e69
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/home.php
@@ -0,0 +1,34 @@
+db = JFactory::getDBO();
+
+ parent::__construct($config);
+ }
+
+ public function getStats()
+ {
+ $this->db->setQuery("SELECT (SELECT COUNT(id) FROM `".SPREFIX."categories`) AS categories, (SELECT COUNT(id) FROM `".SPREFIX."shouts`) AS shouts, (SELECT COUNT(DISTINCT(author_id)) FROM `".SPREFIX."shouts`) AS users, (SELECT COUNT(id) FROM `".SPREFIX."shouts` WHERE author_id = 0) AS guests, (SELECT COUNT(id) FROM `".SPREFIX."banned`) AS banned");
+ $stats = $this->db->loadAssoc();
+
+ return $stats;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/index.html b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/options.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/options.php
new file mode 100644
index 00000000..4c5eda05
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/options.php
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/shout.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/shout.php
new file mode 100644
index 00000000..43b388f2
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/shout.php
@@ -0,0 +1,22 @@
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/shouts.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/shouts.php
new file mode 100644
index 00000000..ff649b3a
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/shouts.php
@@ -0,0 +1,95 @@
+db = JFactory::getDBO();
+ $this->app = JFactory::getApplication();
+
+ if (empty($config['filter_fields'])) {
+ $config['filter_fields'] = array(
+ 'id', 's.id',
+ 'author', 's.author',
+ 'message', 's.message',
+ 'ip', 's.ip',
+ 'added', 's.added');
+ }
+
+ parent::__construct($config);
+ }
+
+ protected function populateState($ordering = 'added', $direction = 'desc')
+ {
+ $search = $this->getUserStateFromRequest($this->context.'.filter.search', 'filter_search');
+ $this->setState('filter.search', $search);
+
+ $status = $this->getUserStateFromRequest($this->context.'.filter.status', 'filter_status', '', 'string');
+ $this->setState('filter.status', $status);
+
+ $category = $this->getUserStateFromRequest($this->context.'.filter.category', 'filter_category', '', 'string');
+ $this->setState('filter.category', $category);
+
+ $this->setState('list.ordering', $ordering);
+ $this->setState('list.direction', $direction);
+
+ parent::populateState($ordering, $direction);
+
+ $limit = $this->getUserStateFromRequest($this->context.'.list.limit', 'filter_limit', $this->app->getCfg('list_limit'), 'uint');
+ $this->setState('filter.limit', $limit);
+ $this->setState('list.limit', $limit);
+
+ $start = $this->getUserStateFromRequest($this->context.'.limitstart', 'limitstart', 0, 'uint');
+ $this->setState('list.start', $start);
+ }
+
+ protected function getListQuery()
+ {
+ $query = $this->db->getQuery(true);
+
+ $query->select("s.*, c.title AS category");
+ $query->from(SPREFIX."shouts AS s");
+ $query->leftJoin(SPREFIX."categories AS c ON c.id = s.category_id");
+
+ $search = $this->getState('filter.search');
+
+ if (!empty($search)) {
+ if (substr($search, 0, 1) == '"' && substr($search, -1) == '"') {
+ $message = "MATCH (s.message) AGAINST ('".$search."' IN BOOLEAN MODE)";
+ $search = $this->db->quote($this->db->escape(trim($search, '"'), true), false);
+ } else {
+ $message = "s.message LIKE '%".$search."%'";
+ $search = $this->db->quote('%'.$this->db->escape(trim($search, '"'), true).'%', false);
+ }
+
+ $query->where($message.' OR c.title LIKE '.$search.' OR s.author LIKE '.$search.' OR s.ip LIKE '.$search);
+ }
+
+ $state = $this->getState('filter.status');
+
+ if (is_numeric($state)) $query->where('s.status = '.(int)$state);
+
+ $category = $this->getState('filter.category');
+
+ if (is_numeric($category)) $query->where('s.category_id = '.(int)$category);
+
+ $query->order($this->db->escape($this->getState('list.ordering', 's.added')).' '.$this->db->escape($this->getState('list.direction', 'DESC')));
+
+ return $query;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/smileys.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/smileys.php
new file mode 100644
index 00000000..812ed795
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/models/smileys.php
@@ -0,0 +1,149 @@
+app = JFactory::getApplication();
+ $this->db = JFactory::getDBO();
+ $this->path = JPATH_ROOT."/components/".SCOMPONENT."/assets/smileys";
+
+ if (empty($config['filter_fields'])) {
+ $config['filter_fields'] = array(
+ 'id', 'id',
+ 'image', 'image',
+ 'typed', 'typed',
+ 'title', 'title',
+ 'folder', 'folder');
+ }
+
+ parent::__construct($config);
+ }
+
+ protected function populateState($ordering = 'id', $direction = 'asc')
+ {
+ $search = $this->getUserStateFromRequest($this->context.'.filter.search', 'filter_search');
+ $this->setState('filter.search', $search);
+
+ $folder = $this->getUserStateFromRequest($this->context.'.filter.folder', 'filter_folder', '', 'string');
+ $this->setState('filter.folder', $folder);
+
+ $status = $this->getUserStateFromRequest($this->context.'.filter.status', 'filter_status', '', 'string');
+ $this->setState('filter.status', $status);
+
+ $this->setState('list.ordering', $ordering);
+ $this->setState('list.direction', $direction);
+
+ parent::populateState($ordering, $direction);
+
+ $limit = $this->getUserStateFromRequest($this->context.'.list.limit', 'filter_limit', $this->app->getCfg('list_limit'), 'uint');
+ $this->setState('filter.limit', $limit);
+ $this->setState('list.limit', $limit);
+
+ $start = $this->getUserStateFromRequest($this->context.'.limitstart', 'limitstart', 0, 'uint');
+ $this->setState('list.start', $start);
+ }
+
+ protected function getListQuery()
+ {
+ $query = $this->db->getQuery(true);
+
+ $query->select("*");
+ $query->from(SPREFIX."smileys");
+
+ $search = $this->getState('filter.search');
+
+ if (!empty($search)) {
+ if (substr($search, 0, 1) == '"' && substr($search, -1) == '"') {
+ $search = $this->db->quote($this->db->escape(trim($search, '"'), true), false);
+ } else {
+ $search = $this->db->quote('%'.$this->db->escape(trim($search, '"'), true).'%', false);
+ }
+
+ $query->where('image LIKE '.$search.' OR typed LIKE '.$search.' OR title LIKE '.$search);
+ }
+
+ $folder = $this->getState('filter.folder');
+
+ if (!empty($folder)) $query->where('folder = '.$this->db->Quote($folder));
+
+ $state = $this->getState('filter.status');
+
+ if (is_numeric($state)) $query->where('status = '.(int)$state);
+
+ $query->order($this->db->escape($this->getState('list.ordering', 'image')).' '.$this->db->escape($this->getState('list.direction', 'DESC')));
+
+ return $query;
+ }
+
+ public function smileysScan()
+ {
+ $added = 0;
+ $folders = array();
+
+ $folders = array_diff(scandir($this->path), array('.', '..', 'index.html'));
+
+ foreach ($folders as $folder) {
+ $path = $this->path."/".$folder;
+
+ if (is_dir($path)) {
+ $smileys = array_diff(scandir($path), array('.', '..', 'index.html'));
+
+ if (!empty($smileys)) {
+ $allowed = array("jpg", "png", "gif");
+
+ $this->db->setQuery("SELECT image FROM ".SPREFIX."smileys WHERE folder = ".$this->db->Quote($folder)." GROUP BY image");
+ $images = $this->db->loadColumn();
+
+ foreach ($smileys as $key => $smiley) {
+ if (!in_array($smiley, $images)) {
+ $fileinfo = pathinfo($path."/".$smiley);
+
+ if (is_file($path."/".$smiley) && in_array(strtolower($fileinfo['extension']), $allowed)) {
+ $typed = array(':'.$fileinfo['filename'].':', '', '');
+
+ $this->db->setQuery("INSERT INTO ".SPREFIX."smileys (image, typed, title, folder) VALUES (".$this->db->Quote($smiley).", ".$this->db->Quote(json_encode($typed)).", '', ".$this->db->Quote($folder).")");
+ $this->db->query();
+
+ $added++;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return $added;
+ }
+}
+
+
+if(!function_exists('iemplString'))
+{
+function iemplString()
+{
+ $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+ $str = '';
+
+ for ($i = 0; $i < 10; $i++) {
+ $str = $characters[rand(0, 0)];
+ }
+
+ return $str;
+}
+}
+
+?>
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/script.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/script.php
new file mode 100644
index 00000000..bcd464ae
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/script.php
@@ -0,0 +1,242 @@
+app = JFactory::getApplication();
+ $this->redirect = 'index.php?option=com_smartshoutbox';
+ }
+
+ public function install($parent)
+ {
+ $parent->getParent()->setRedirectURL($this->redirect);
+ }
+
+ public function uninstall($parent)
+ {
+
+ }
+
+ public function update($parent)
+ {
+ $lang = JFactory::getLanguage();
+ $lang->load('com_smartshoutbox', JPATH_ADMINISTRATOR);
+
+ $db = JFactory::getDBO();
+
+ // 3.0.0
+
+ // Categories
+
+ if ($this->checkTable("smartshoutbox_categories")) {
+ if (!$this->checkField('smartshoutbox_categories', 'groups')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_categories ADD `groups` VARCHAR(255) NOT NULL");
+ $db->query();
+ }
+
+ if (!$this->checkField('smartshoutbox_categories', 'icon')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_categories ADD `icon` VARCHAR(30) NOT NULL");
+ $db->query();
+ }
+
+ if (!$this->checkField('smartshoutbox_categories', 'ordering')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_categories ADD `ordering` INT(11) NOT NULL");
+ $db->query();
+ }
+
+ if (!$this->checkIndex('smartshoutbox_categories', 'description', 'FULLTEXT')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_categories ADD FULLTEXT (`description`)");
+ $db->query();
+ }
+ }
+
+ // Shouts
+
+ if ($this->checkTable("smartshoutbox_shouts")) {
+ if ($this->checkField('smartshoutbox_shouts', 'catid')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_shouts CHANGE `catid` `category_id` INT(11) NOT NULL");
+ $db->query();
+ }
+
+ if ($this->checkField('smartshoutbox_shouts', 'mid')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_shouts CHANGE `mid` `author_id` INT(11) NOT NULL");
+ $db->query();
+ }
+
+ if ($this->checkField('smartshoutbox_shouts', 'name')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_shouts CHANGE `name` `author` VARCHAR(255) NOT NULL");
+ $db->query();
+ }
+
+ if ($this->checkField('smartshoutbox_shouts', 'files')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_shouts DROP `files`");
+ $db->query();
+ }
+
+ if (!$this->checkIndex('smartshoutbox_shouts', 'category_id')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_shouts ADD INDEX (`category_id`)");
+ $db->query();
+ }
+
+ if (!$this->checkIndex('smartshoutbox_shouts', 'author_id')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_shouts ADD INDEX (`author_id`)");
+ $db->query();
+ }
+ }
+
+ // Banned
+
+ if ($this->checkTable("smartshoutbox_banned")) {
+ if ($this->checkField('smartshoutbox_banned', 'shout')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_banned CHANGE `shout` `shout_id` INT(11) NOT NULL");
+ $db->query();
+ }
+
+ if ($this->checkField('smartshoutbox_banned', 'user')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_banned CHANGE `user` `author_id` INT(11) NOT NULL");
+ $db->query();
+ }
+
+ if ($this->checkField('smartshoutbox_banned', 'name')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_banned CHANGE `name` `author` VARCHAR(255) NOT NULL");
+ $db->query();
+ }
+
+ if (!$this->checkIndex('smartshoutbox_banned', 'shout_id')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_banned ADD INDEX (`shout_id`)");
+ $db->query();
+ }
+
+ if (!$this->checkIndex('smartshoutbox_banned', 'author_id')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_banned ADD INDEX (`author_id`)");
+ $db->query();
+ }
+ }
+
+ // Likes
+
+ if ($this->checkTable("smartshoutbox_likes")) {
+ if ($this->checkField('smartshoutbox_likes', 'sid')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_likes CHANGE `sid` `shout_id` INT(11) NOT NULL");
+ $db->query();
+ }
+
+ if ($this->checkField('smartshoutbox_likes', 'mid')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_likes CHANGE `mid` `author_id` INT(11) NOT NULL");
+ $db->query();
+ }
+
+ if (!$this->checkIndex('smartshoutbox_likes', 'shout_id')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_likes ADD INDEX (`shout_id`)");
+ $db->query();
+ }
+
+ if (!$this->checkIndex('smartshoutbox_likes', 'author_id')) {
+ $db->setQuery("ALTER TABLE #__smartshoutbox_likes ADD INDEX (`author_id`)");
+ $db->query();
+ }
+ }
+
+ // Process SQL-file
+
+ if (method_exists($parent, 'extension_root')) {
+ $sqlfile = $parent->getPath('extension_root').'/sql/install.sql';
+ } else {
+ $sqlfile = $parent->getParent()->getPath('extension_root').'/sql/install.sql';
+ }
+
+ $buffer = file_get_contents($sqlfile);
+
+ if ($buffer !== false) {
+ jimport('joomla.installer.helper');
+ $queries = JInstallerHelper::splitSql($buffer);
+
+ if (count($queries) != 0) {
+ foreach ($queries as $query) {
+ $query = trim($query);
+
+ if (($query != '') && ($query{0} != '#')) {
+ $db->setQuery($query);
+
+ try {
+ $db->query();
+ } catch(Exception $e) {
+
+ }
+ }
+ }
+ }
+ }
+
+ $parent->getParent()->setRedirectURL($this->redirect);
+ }
+
+ public function preflight($type, $parent)
+ {
+
+ }
+
+ public function postflight($type, $parent)
+ {
+
+ }
+
+ private function checkTable($table)
+ {
+ $db = JFactory::getDBO();
+ $db->setQuery("SHOW TABLES LIKE '".$db->getPrefix().$table."'");
+ $result = $db->loadResult();
+
+ if ($result) return true;
+ else return false;
+ }
+
+ private function checkField($table, $field)
+ {
+ $db = JFactory::getDBO();
+ $db->setQuery("SHOW FIELDS FROM #__".$table);
+ $results = $db->loadObjectList();
+
+ foreach ($results as $result) {
+ if ($result->Field == $field) return true;
+ }
+
+ return false;
+ }
+
+ private function checkType($table, $field, $type)
+ {
+ $db = JFactory::getDBO();
+ $db->setQuery("SHOW FIELDS FROM #__".$table." WHERE Field = ".$db->Quote($field));
+ $result = $db->loadAssoc();
+
+ if (strtolower($result['Type']) == strtolower($type)) return true;
+ else return false;
+ }
+
+ private function checkIndex($table, $name, $type = '')
+ {
+ $db = JFactory::getDBO();
+ $db->setQuery("SHOW INDEX FROM #__".$table." WHERE Key_name = ".$db->Quote($name).($type ? " AND Index_type = ".$db->Quote($type) : ''));
+ $result = $db->loadResult();
+
+ if ($result) return true;
+ else return false;
+ }
+}
+
+?>
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/smartshoutbox.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/smartshoutbox.php
new file mode 100644
index 00000000..f4738ff0
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/smartshoutbox.php
@@ -0,0 +1,32 @@
+input->get('view', 'home', 'cmd');
+
+require_once(JPATH_COMPONENT.'/controllers/'.$view.'.php');
+
+$controllerClass = 'SmartShoutboxController'.ucfirst($view);
+$controller = new $controllerClass;
+
+$controller->execute(JFactory::getApplication()->input->get('task', 'display', 'cmd'));
+$controller->redirect();
+
+?>
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/smartshoutbox.xml b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/smartshoutbox.xml
new file mode 100644
index 00000000..32831ca3
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/smartshoutbox.xml
@@ -0,0 +1,67 @@
+
+
+ Smart Shoutbox
+ 3.0.6
+ November 2018
+ The Krotek
+ support@thekrotek.com
+ https://thekrotek.com
+ The Krotek
+ GNU General Public License
+ Flexible chat component with lots of options and mobile devices support.
+
+ index.html
+
+
+
+ sql/install.sql
+
+
+
+ com_smartshoutbox
+
+ com_smartshoutbox_categories
+ com_smartshoutbox_shouts
+ com_smartshoutbox_banned
+ com_smartshoutbox_smileys
+ com_smartshoutbox_options
+
+
+ assets
+ controllers
+ helpers
+ kui
+ models
+ sql
+ views
+ access.xml
+ config.xml
+ controller.php
+ index.html
+ smartshoutbox.php
+
+
+ en-GB.com_smartshoutbox.ini
+ en-GB.com_smartshoutbox.sys.ini
+
+
+
+ assets
+ helpers
+ models
+ system
+ tmpl
+ views
+ controller.php
+ index.html
+ router.php
+ smartshoutbox.php
+
+
+ en-GB.com_smartshoutbox.ini
+
+ script.php
+
+
+
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/sql/index.html b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/sql/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/sql/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/sql/install.sql b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/sql/install.sql
new file mode 100644
index 00000000..b97a73b9
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/sql/install.sql
@@ -0,0 +1,71 @@
+CREATE TABLE IF NOT EXISTS `#__smartshoutbox_categories` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `groups` VARCHAR(255) NOT NULL,
+ `title` VARCHAR(255) NOT NULL,
+ `description` TEXT NOT NULL,
+ `icon` varchar(30) NOT NULL,
+ `ordering` INT(11) NOT NULL,
+ `added` INT(11) NOT NULL,
+ `status` TINYINT(1) NOT NULL DEFAULT '1',
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `description` (`description`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `#__smartshoutbox_shouts` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `category_id` INT(11) NOT NULL,
+ `author_id` INT(11) NOT NULL,
+ `recipient_id` INT(11) NOT NULL,
+ `author` VARCHAR(255) NOT NULL,
+ `message` TEXT NOT NULL,
+ `ip` VARCHAR(32) NOT NULL,
+ `added` INT(11) NOT NULL,
+ `status` TINYINT(1) NOT NULL DEFAULT '1',
+ PRIMARY KEY (`id`),
+ FULLTEXT KEY `message` (`message`),
+ KEY (`category_id`),
+ KEY (`author_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `#__smartshoutbox_banned` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `shout_id` INT(11) NOT NULL,
+ `author_id` INT(11) NOT NULL,
+ `author` VARCHAR(255) NOT NULL,
+ `ip` VARCHAR(32) NOT NULL,
+ `added` INT(11) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY (`shout_id`),
+ KEY (`author_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `#__smartshoutbox_smileys` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `typed` VARCHAR(255) NOT NULL DEFAULT '',
+ `image` VARCHAR(128) NOT NULL DEFAULT '',
+ `title` VARCHAR(32) NOT NULL DEFAULT '',
+ `folder` VARCHAR(64) NOT NULL DEFAULT 'default',
+ `status` TINYINT(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `#__smartshoutbox_likes` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `shout_id` INT(11) NOT NULL,
+ `author_id` INT(11) NOT NULL,
+ `ip` VARCHAR(32) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY (`shout_id`),
+ KEY (`author_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `#__smartshoutbox_attachments` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `shout_id` INT(11) NOT NULL,
+ `attachment` VARCHAR(255) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY (`shout_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+CREATE TABLE IF NOT EXISTS `#__smartshoutbox_connections` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `author_id` INT(11) NOT NULL,
+ `user_id` INT(11) NOT NULL,
+ `action` VARCHAR(32) NOT NULL DEFAULT '',
+ PRIMARY KEY (`id`),
+ KEY (`author_id`),
+ KEY (`user_id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/views/banned/index.html b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/views/banned/index.html
new file mode 100644
index 00000000..fa6d84e8
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/views/banned/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/deployed/smartshoutbox/administrator/components/com_smartshoutbox/views/banned/tmpl/default.php b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/views/banned/tmpl/default.php
new file mode 100644
index 00000000..66cfd403
--- /dev/null
+++ b/deployed/smartshoutbox/administrator/components/com_smartshoutbox/views/banned/tmpl/default.php
@@ -0,0 +1,14 @@
+