Here is the code. IE7 spouts an "'active.0' is null or not an object" error on line 39, which is:
input.trigger("activate.autocomplete", [$.data(active[0], "originalObject")]); $("body").trigger("off.autocomplete");
Works perfectly in Firefox/Chrome/Opera. Any ideas? Many thanks and much appreciated.
/* jQuery Autocomplete
* Version 1.0
* Written by Yehuda Katz (wycats#gmail.com) and Rein Henrichs (reinh#reinh.com)
* #requires jQuery v1.2, jQuery dimensions plugin
*
* Copyright 2007 Yehuda Katz, Rein Henrichs
* Dual licensed under the MIT and GPL licenses:
* hxxp://www.opensource.org/licenses/mit-license.php
* hxxp://www.gnu.org/licenses/gpl.html
*
*/
/*
* #description Form autocomplete plugin using preloaded or Ajax JSON data source
*
* #example $('input#user-name').autocomplete({list: ["quentin", "adam", "admin"]})
* #desc Simple autocomplete with basic JSON data source
*
* #example $('input#user-name').autocomplete({ajax: "/usernames.js"})
* #desc Simple autocomplete with Ajax loaded JSON data source
*
*/
(function($) {
$.ui = $.ui || {}; $.ui.autocomplete = $.ui.autocomplete || {}; var active;
$.fn.autocompleteMode = function(container, input, size, opt) {
var original = input.val(); var selected = -1; var self = this;
$.data(document.body, "autocompleteMode", true);
$("body").one("cancel.autocomplete", function() {
input.trigger("cancel.autocomplete"); $("body").trigger("off.autocomplete"); input.val(original);
});
$("body").one("activate.autocomplete", function() {
input.trigger("activate.autocomplete", [$.data(active[0], "originalObject")]); $("body").trigger("off.autocomplete");
});
$("body").one("off.autocomplete", function(e, reset) {
container.remove();
$.data(document.body, "autocompleteMode", false);
input.unbind("keydown.autocomplete");
$("body").add(window).unbind("click.autocomplete").unbind("cancel.autocomplete").unbind("activate.autocomplete");
});
// If a click bubbles all the way up to the window, close the autocomplete
$(window).bind("click.autocomplete", function() { $("body").trigger("cancel.autocomplete"); });
var select = function() {
active = $("> *", container).removeClass("active").slice(selected, selected + 1).addClass("active");
input.trigger("itemSelected.autocomplete", [$.data(active[0], "originalObject")]);
input.val(opt.insertText($.data(active[0], "originalObject")));
};
container.mouseover(function(e) {
// If you hover over the container, but not its children, return
if(e.target == container[0]) return;
// Set the selected item to the item hovered over and make it active
selected = $("> *", container).index($(e.target).is('li') ? $(e.target)[0] : $(e.target).parents('li')[0]); select();
}).bind("click.autocomplete", function(e) {
$("body").trigger("activate.autocomplete"); $.data(document.body, "suppressKey", false);
});
input
.bind("keydown.autocomplete", function(e) {
if(e.which == 27) { $("body").trigger("cancel.autocomplete"); }
else if(e.which == 13) { $("body").trigger("activate.autocomplete"); }
else if(e.which == 40 || e.which == 9 || e.which == 38) {
switch(e.which) {
case 40:
case 9:
selected = selected >= size - 1 ? 0 : selected + 1; break;
case 38:
selected = selected <= 0 ? size - 1 : selected - 1; break;
default: break;
}
select();
} else { return true; }
$.data(document.body, "suppressKey", true);
});
};
$.fn.autocomplete = function(opt) {
opt = $.extend({}, {
timeout: 1000,
getList: function(input) { input.trigger("updateList", [opt.list]); },
template: function(str) { return "<li>" + opt.insertText(str) + "</li>"; },
insertText: function(str) { return str; },
match: function(typed) { return this.match(new RegExp(typed)); },
wrapper: "<ul class='jq-ui-autocomplete'></ul>"
}, opt);
if($.ui.autocomplete.ext) {
for(var ext in $.ui.autocomplete.ext) {
if(opt[ext]) {
opt = $.extend(opt, $.ui.autocomplete.ext[ext](opt));
delete opt[ext];
}
} }
return this.each(function() {
$(this)
.keypress(function(e) {
var typingTimeout = $.data(this, "typingTimeout");
if(typingTimeout) window.clearInterval(typingTimeout);
if($.data(document.body, "suppressKey"))
return $.data(document.body, "suppressKey", false);
else if($.data(document.body, "autocompleteMode") && e.charCode < 32 && e.keyCode != 8 && e.keyCode != 46) return false;
else {
$.data(this, "typingTimeout", window.setTimeout(function() {
$(e.target).trigger("autocomplete");
}, opt.timeout));
}
})
.bind("autocomplete", function() {
var self = $(this);
self.one("updateList", function(e, list) {
list = $(list)
.filter(function() { return opt.match.call(this.toLowerCase(), self.val()); })
.map(function() {
var node = $(opt.template(this))[0];
$.data(node, "originalObject", this);
return node;
});
$("body").trigger("off.autocomplete");
if(!list.length) return false;
var container = list.wrapAll(opt.wrapper).parents(":last").children();
var offset = self.offset();
opt.container = container
.css({top: offset.top + self.outerHeight(), left: offset.left, width: self.width()})
.appendTo("body");
$("body").autocompleteMode(container, self, list.length, opt);
});
opt.getList(self);
});
});
};
})(jQuery);
Check out:
http://github.com/istruble/jquery-autocomplete/commit/bdc926bd2c18c3ebab4e31463a8ae899fd761316#diff-1
It is a version of jquery.ui.autocomplete.js with most of the IE 7 issues fixed. I found a few more issues which I listed at the bottom along with how to fix them.
Here is my code that works javascript first:
$(".student_search").autocomplete("student_search.php", {
minChars: 2,
cacheLength: 20,
matchContains: true,
highlightItem: true,
parse: function(data) {
return $.map(eval(data), function(row) {
return {
data: row,
value: row.studentname, //value being searched for
result: row.studentidnumber //value in text input
}
});
},
formatItem: function(row, i, max, term) {
return "<span style='font-size: 110%;'>" + row.studentname + "</span><br/>" + "ID: " + row.studentidnumber + ", " + " Grade: " + row.studentgradenumber;
},
formatResult: function(row, i, max){
return row.studentidnumber;
}
});
});
Here is the code in the PHP file. It prints a JSON object with the data.
if(isset($_GET['q'])){
require_once("php/mysql.connect.php");
$request = strtolower($_GET['q']);
$query = mysql_query("SELECT
CONCAT(studentfname, ' ', studentlname, '')
AS studentname, studentidnumber,
CONCAT(studentgradenumber, 'th')
AS studentgradenumber
FROM studentinfo
WHERE studentlname LIKE '%".$request."%'
OR studentfname LIKE '%".$request."%'
OR studentidnumber LIKE '%".$request."%'") or die(mysql_error());
$results = array();
$i = 0;
while($row = mysql_fetch_assoc($query)) //fetch each result using the column name as the array key
{
foreach($row as $column=>$val) //loop through each column
{
$results[$i][$column] = $val; //build array using incremental row # and column name
}
$i++; //increase the row counter
}
print json_encode($results);
}
The JSON object that is printed is:
[{"studentname":"Joe Schmo","studentidnumber":"123456","studentgradenumber":"11th"}]
so row.studentname returns Joe Schmo. Where row is the name of the variable in the function and studentname is the name of the key from the JSON object.
Cheers!
I had problems with autocompletion of jquery ui version 1.8.9 and IE7. I use 1.8.16 now and it works.
Related
I created autocomplete listbox from js.I download this js.
but due to this js implementation in my code...
my save and search button not working....
but when I comment this js file...submit button works properly..
but this js is also necessary for me to make listbox as autocomplete textbox...
plz suggest me what to change in this js..to make both button and listbox works.
my save button code
<?php
if($_POST && isset($_POST['submit']))
{}
?>
below is my listbox
<select class="special-flexselect" id="society" name="society" tabindex="5" >
<option value="" ></option>
<?php foreach ($society as $soc){ ?>
<option value="<?php echo $soc["society"]; ?>"><?php echo $soc["society"]; ?></option>
<?php }?>
</select>
below is my js code
/**
* flexselect: a jQuery plugin, version: 0.6.0 (2014-08-05)
* #requires jQuery v1.3 or later
*
* FlexSelect is a jQuery plugin that makes it easy to convert a select box into
* a Quicksilver-style, autocompleting, flex matching selection tool.
*
* For usage and examples, visit:
* http://rmm5t.github.io/jquery-flexselect/
*
* Licensed under the MIT:
* http://www.opensource.org/licenses/mit-license.php
*
* Copyright (c) 2009-2012, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/
(function($) {
$.flexselect = function(select, options) { this.init(select, options); };
$.extend($.flexselect.prototype, {
settings: {
allowMismatch: false,
allowMismatchBlank: true, // If "true" a user can backspace such that the value is nothing (even if no blank value was provided in the original criteria)
sortBy: 'score', // 'score' || 'name'
preSelection: true,
hideDropdownOnEmptyInput: false,
selectedClass: "flexselect_selected",
dropdownClass: "flexselect_dropdown",
showDisabledOptions: false,
inputIdTransform: function(id) { return id + "_flexselect"; },
inputNameTransform: function(name) { return; },
dropdownIdTransform: function(id) { return id + "_flexselect_dropdown"; }
},
select: null,
input: null,
dropdown: null,
dropdownList: null,
cache: [],
results: [],
lastAbbreviation: null,
abbreviationBeforeFocus: null,
selectedIndex: 0,
picked: false,
allowMouseMove: true,
dropdownMouseover: false, // Workaround for poor IE behaviors
indexOptgroupLabels: false,
init: function(select, options) {
this.settings = $.extend({}, this.settings, options);
this.select = $(select);
this.preloadCache();
this.renderControls();
this.wire();
},
preloadCache: function() {
var name, group, text, disabled;
var indexGroup = this.settings.indexOptgroupLabels;
this.cache = this.select.find("option").map(function() {
name = $(this).text();
group = $(this).parent("optgroup").attr("label");
text = indexGroup ? [name, group].join(" ") : name;
disabled = $(this).parent("optgroup").attr("disabled") || $(this).attr('disabled');
return { text: $.trim(text), name: $.trim(name), value: $(this).val(), disabled: disabled, score: 0.0 };
});
},
renderControls: function() {
var selected = this.settings.preSelection ? this.select.find("option:selected") : null;
this.input = $("<input type='text' autocomplete='off' />").attr({
id: this.settings.inputIdTransform(this.select.attr("id")),
name: this.settings.inputNameTransform(this.select.attr("name")),
accesskey: this.select.attr("accesskey"),
tabindex: this.select.attr("tabindex"),
style: this.select.attr("style"),
placeholder: this.select.attr("data-placeholder")
}).addClass(this.select.attr("class")).val($.trim(selected ? selected.text(): '')).css({
visibility: 'visible'
});
this.dropdown = $("<div></div>").attr({
id: this.settings.dropdownIdTransform(this.select.attr("id"))
}).addClass(this.settings.dropdownClass);
this.dropdownList = $("<ul></ul>");
this.dropdown.append(this.dropdownList);
this.select.after(this.input).hide();
$("body").append(this.dropdown);
},
wire: function() {
var self = this;
this.input.click(function() {
self.lastAbbreviation = null;
self.focus();
});
this.input.mouseup(function(event) {
// This is so Safari selection actually occurs.
event.preventDefault();
});
this.input.focus(function() {
self.abbreviationBeforeFocus = self.input.val();
self.input.select();
if (!self.picked) self.filterResults();
});
this.input.blur(function() {
if (!self.dropdownMouseover) {
self.hide();
if (self.settings.allowMismatchBlank && $.trim($(this).val()) == '')
self.setValue('');
if (!self.settings.allowMismatch && !self.picked)
self.reset();
}
if (self.settings.hideDropdownOnEmptyInput)
self.dropdownList.show();
});
this.dropdownList.mouseover(function(event) {
if (!self.allowMouseMove) {
self.allowMouseMove = true;
return;
}
if (event.target.tagName == "LI") {
var rows = self.dropdown.find("li");
self.markSelected(rows.index($(event.target)));
}
});
this.dropdownList.mouseleave(function() {
self.markSelected(-1);
});
this.dropdownList.mouseup(function(event) {
self.pickSelected();
self.focusAndHide();
});
this.dropdown.mouseover(function(event) {
self.dropdownMouseover = true;
});
this.dropdown.mouseleave(function(event) {
self.dropdownMouseover = false;
});
this.dropdown.mousedown(function(event) {
event.preventDefault();
});
this.input.keyup(function(event) {
switch (event.keyCode) {
case 13: // return
event.preventDefault();
self.pickSelected();
self.focusAndHide();
break;
case 27: // esc
event.preventDefault();
self.reset();
self.focusAndHide();
break;
default:
self.filterResults();
break;
}
if (self.settings.hideDropdownOnEmptyInput){
if(self.input.val() == "")
self.dropdownList.hide();
else
self.dropdownList.show();
}
});
this.input.keydown(function(event) {
switch (event.keyCode) {
case 9: // tab
self.pickSelected();
self.hide();
break;
case 33: // pgup
event.preventDefault();
self.markFirst();
break;
case 34: // pgedown
event.preventDefault();
self.markLast();
break;
case 38: // up
event.preventDefault();
self.moveSelected(-1);
break;
case 40: // down
event.preventDefault();
self.moveSelected(1);
break;
case 13: // return
case 27: // esc
event.preventDefault();
event.stopPropagation();
break;
}
});
var input = this.input;
this.select.change(function () {
input.val($.trim($(this).find('option:selected').text()));
});
},
filterResults: function() {
var showDisabled = this.settings.showDisabledOptions;
var abbreviation = this.input.val();
if (abbreviation == this.lastAbbreviation) return;
var results = [];
$.each(this.cache, function() {
if (this.disabled && !showDisabled) return;
this.score = LiquidMetal.score(this.text, abbreviation);
if (this.score > 0.0) results.push(this);
});
this.results = results;
if (this.settings.sortBy == 'score')
this.sortResultsByScore();
else if (this.settings.sortBy == 'name')
this.sortResultsByName();
this.renderDropdown();
this.markFirst();
this.lastAbbreviation = abbreviation;
this.picked = false;
this.allowMouseMove = false;
},
sortResultsByScore: function() {
this.results.sort(function(a, b) { return b.score - a.score; });
},
sortResultsByName: function() {
this.results.sort(function(a, b) { return a.name < b.name ? -1 : (a.name > b.name ? 1 : 0); });
},
renderDropdown: function() {
var showDisabled = this.settings.showDisabledOptions;
var dropdownBorderWidth = this.dropdown.outerWidth() - this.dropdown.innerWidth();
var inputOffset = this.input.offset();
this.dropdown.css({
width: (this.input.outerWidth() - dropdownBorderWidth) + "px",
top: (inputOffset.top + this.input.outerHeight()) + "px",
left: inputOffset.left + "px",
maxHeight: ''
});
var html = '';
var disabledAttribute = '';
$.each(this.results, function() {
if (this.disabled && !showDisabled) return;
disabledAttribute = this.disabled ? ' class="disabled"' : '';
html += '<li' + disabledAttribute + '>' + this.name + '</li>';
});
this.dropdownList.html(html);
this.adjustMaxHeight();
this.dropdown.show();
},
adjustMaxHeight: function() {
var maxTop = $(window).height() + $(window).scrollTop() - this.dropdown.outerHeight();
var top = parseInt(this.dropdown.css('top'), 10);
this.dropdown.css('max-height', top > maxTop ? (Math.max(0, maxTop - top + this.dropdown.innerHeight()) + 'px') : '');
},
markSelected: function(n) {
if (n < 0 || n >= this.results.length) return;
var rows = this.dropdown.find("li");
rows.removeClass(this.settings.selectedClass);
var row = $(rows[n]);
if (row.hasClass('disabled')) {
this.selectedIndex = null;
return;
}
this.selectedIndex = n;
row.addClass(this.settings.selectedClass);
var top = row.position().top;
var delta = top + row.outerHeight() - this.dropdown.height();
if (delta > 0) {
this.allowMouseMove = false;
this.dropdown.scrollTop(this.dropdown.scrollTop() + delta);
} else if (top < 0) {
this.allowMouseMove = false;
this.dropdown.scrollTop(Math.max(0, this.dropdown.scrollTop() + top));
}
},
pickSelected: function() {
var selected = this.results[this.selectedIndex];
if (selected && !selected.disabled) {
this.input.val(selected.name);
this.setValue(selected.value);
this.picked = true;
} else if (this.settings.allowMismatch) {
this.setValue.val("");
} else {
this.reset();
}
},
setValue: function(val) {
if (this.select.val() === val) return;
this.select.val(val).change();
},
hide: function() {
this.dropdown.hide();
this.lastAbbreviation = null;
},
moveSelected: function(n) { this.markSelected(this.selectedIndex+n); },
markFirst: function() { this.markSelected(0); },
markLast: function() { this.markSelected(this.results.length - 1); },
reset: function() { this.input.val(this.abbreviationBeforeFocus); },
focus: function() { this.input.focus(); },
focusAndHide: function() { this.focus(); this.hide(); }
});
$.fn.flexselect = function(options) {
this.each(function() {
if (this.tagName == "SELECT") new $.flexselect(this, options);
});
return this;
};
})(jQuery);
find this in your js page and Remove this from js file,bcoz this shoud stop user to submit form data
$("form").submit(function() {
alert($(this).serialize());
return false;
});
Ok i have site with old version of jquery, then i imported modul, where i have newer version of jquery, in my modul page i have this line of jquery
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
Somehow i have conflict. I cant remove old version from header cuz some function dont work, in the other side in my module page if i remove newer version spinner function dont work. I cant use both jquery versions in same time. is there some way how to resolve this conflict.
Code where i have error is: In this script i need older version not before loaded new version jquery-1.10.2.js
var notice = new Array();
$(document).ready( function() {
/*setTimeout(function(){ $(".notice").fadeTo('slow',1), 500; });
setTimeout(function(){ $(".notice").fadeTo('slow',0.4); }, 1500);*/
/*setTimeout(function(){
$(".notice").animate( { backgroundColor: '#B8B8B8' }, 1000)
});*/
setTimeout(function(){
$(".notice").animate( { backgroundColor: '#e0e0e0' }, 1000)
});
$.safetynet({
message : isDirtyWarning
});
});
/**
* Funkcija ce Sve vrednosti Combo Boksa upisati u hidden polje razdvojeno
* zarezom
*
* #param hidden_field_id
* #return
*/
function ComboFieldsToValue(combo_selector, hidden_field_id) {
var vrednosti = "";
$(combo_selector + ' option').each( function() {
vrednosti += $(this).val() + ',';
});
$(hidden_field_id).attr( {
value :vrednosti.substring(0, vrednosti.length - 1)
});
// alert($(hidden_field_id).attr("value"));
}
/**
* Proverava da li Combo ima item sa zadatom vrednoscu
* Vraca true ako ima, false ako nema
* #param combo_selector
* #param key
* #return
*/
function IsItemInCombo(combo_selector, key) {
var is_in_combo = false;
$(combo_selector + ' option').each( function() {
if ($(this).val() == key) {
is_in_combo = true;
}
});
return is_in_combo;
}
/**
* Potrda brisanja
* #param link
* #return
*/
function PotvrdiBrisanje(link, str) {
if(str == "") str = "Potvrdi brisanje?";
if (confirm("" + str)) {
document.location = link;
}
}
function ajaxPotvrdiBrisanje(link, str, autoconfirm, flexi_id) {
if(str == "") str = "Potvrdi brisanje?";
if(autoconfirm == "") autoconfirm = false;
if(flexi_id == "" || !flexi_id) flexi_id = 'flex1';
if (autoconfirm || confirm("" + str)) {
$.ajax({
url: link,
async : false,
success: function(data) {
if (data.substr(0, 4) == "msg:") {
notice[notice.length] = data.substr(4,data.length);
}
}
});
}
return false;
}
function addToNotice(data)
{
if (data.substr(0, 4) == "msg:") {
notice[notice.length] = data.substr(4,data.length);
}
}
function PrikaziNotice() {
if (notice.length == 0) return;
$('p.flexy_notice').html('');
$('p.flexy_notice').css({ backgroundColor: '#FB2D2B' });
$('p.flexy_notice').hide('');
/*
* Uknjamoi osmnovni notce
*
*/
if ($('.notice').length != 0) {
$('.notice').hide();
}
html = "";
for ( var i in notice ) {
html += '<p>' + notice[i] + '</p>';
}
$('p.flexy_notice').html(html);
$('p.flexy_notice').show();
$(".flexy_notice").animate( { backgroundColor: '#e0e0e0' }, 1000);
notice = new Array();
}
function reloadFlexi() { $("#flex1").flexReload(); }
function ShowAudit(id) {
$(".audit_" + id).toggle();
}
function setDirtyTiny(){
$.safetynet.raiseChange($('textarea'));
}
Can someone explain me how to adjust this js file
If you need to run two versions of jquery, you can use noconflict.
Example:
<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
<script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script>
<script>
newJquery = jQuery.noConflict(true);
newJquery(document).ready( function() {
...
...
Here is a blog dealing with this problem:
http://blog.nemikor.com/2009/10/03/using-multiple-versions-of-jquery/
Just add this to your html page in which the conflict occurs:
<script>
$.noConflict();
</script>
I need help in creating a plugin for rich text editor in Adobe cq 5 to add an image, pdf, video, ppt or any file into rich text editor.
The existing rte plugins that are available are findreplace, undo, spellcheck, table etc
How to create a plugin to add a file to rich text editor?
The plugins are an ext js files. Appreciate if any one can suggest answer. It will be of great help.
Thanks
I added a custom drop down into my RTE. It was used to add values to the editor on selecting values from it. I think this might help you solve your issue because similarly you can create your required plugin.
Please refer comments next to the methods for your reference.
/**
* Placeholder Plugin
*/
var keyvalueEnteries = [];
var newText;
var doc;
var range
CUI.rte.plugins.PlaceholderPlugin = new Class({
toString: "PlaceholderPlugin",
extend: CUI.rte.plugins.Plugin,
/**
* #private
*/
cachedFormats: null,
/**
* #private
*/
formatUI: null,
getFeatures: function() {
return [ "Myparaformat" ];
},
/**
* #private
*
*/
getKeys: function() {
var com = CUI.rte.Common;
if (this.cachedFormats == null) {
this.cachedFormats = this.config.formats || { };
com.removeJcrData(this.cachedFormats);
this.cachedFormats = com.toArray(this.cachedFormats, "tag", "description");
}
return this.cachedFormats;
},
initializeUI: function(tbGenerator) {
var plg = CUI.rte.plugins;
var ui = CUI.rte.ui;
if (this.isFeatureEnabled("placeHolder")) {
this.formatUI = tbGenerator.createParaFormatter("placeHolder", this,null,this.getKeys());
tbGenerator.addElement("placeHolder", plg.Plugin.SORT_PARAFORMAT, this.formatUI,
10);
}
},
notifyPluginConfig: function(pluginConfig) { //This function gets executed once on load of RTE for the first time
var url = pluginConfig.sourceURL;
keyvalueEnteries = CQ.HTTP.eval(url);
keyvalueEnteries = JSON.stringify(keyvalueEnteries);
if(keyvalueEnteries == undefined){
keyvalueEnteries = '[{"key":"","value":"None"}]';
}
pluginConfig = pluginConfig || { };
//creating JSON sttructure
var placeholderJSON = '{"formats":' + keyvalueEnteries + '}';
var placeHolderVals = eval('(' + placeholderJSON + ')');
var defaults = placeHolderVals;
if (pluginConfig.formats) {
delete defaults.formats;
}
CUI.rte.Utils.applyDefaults(pluginConfig, defaults);
this.config = pluginConfig;
},
execute: function(cmd) { // This function gets executed when there is change in the state of custom plugin/drop down
if (this.formatUI) {
var formatId = this.formatUI.getSelectedFormat();
if (formatId && range != undefined) {
var placeholderElement = "";
if(formatId == 'none' && range.collapsed == false){//checks if None is selected in placeholder and the text is selected
range.deleteContents();
}else if(formatId != 'none'){
placeholderElement = document.createTextNode(" ${" + formatId + "} ");
range.insertNode(placeholderElement); //INSERTS PLACEHOLDER AT CURRENT CARET LOCATION
range.setStartAfter(placeholderElement);//INSERTS CURSOR AT THE END OF CURRENT PLACEHOLDER IF PLACEHOLDER IS SELECTED AGAIN
}
}
}
},
updateState: function(selDef) { // This function gets executed on click on the editor space in RTE
doc = selDef.editContext.doc; //GET THE DOCUMENT INSIDE THE IFRAME
range = doc.getSelection().getRangeAt(0); //GETS CURRENT CARET POSITION
}
});
//register plugin
CUI.rte.plugins.PluginRegistry.register("placeholder",
CUI.rte.plugins.PlaceholderPlugin);
CUI.rte.ui.ext.ParaFormatterImpl = new Class({
toString: "ParaFormatterImpl",
extend: CUI.rte.ui.TbParaFormatter,
// Interface implementation ------------------------------------------------------------
addToToolbar: function(toolbar) {
var com = CUI.rte.Common;
this.toolbar = toolbar;
if (com.ua.isIE) {
// the regular way doesn't work for IE anymore with Ext 3.1.1, hence working
// around
var helperDom = document.createElement("span");
helperDom.innerHTML = "<select class=\"x-placeholder-select\">"
+ this.createFormatOptions() + "</select>";
this.formatSelector = CQ.Ext.get(helperDom.childNodes[0]);
} else {
this.formatSelector = CQ.Ext.get(CQ.Ext.DomHelper.createDom({
tag: "select",
cls: "x-placeholder-select",
html: this.createFormatOptions()
}));
}
this.initializeSelector();
toolbar.add(
CQ.I18n.getMessage("Placeholder"), // Type the name you want to appear in RTE for the custom plugin /drop down
" ",
this.formatSelector.dom);
},
/**
* Creates HTML code for rendering the options of the format selector.
* #return {String} HTML code containing the options of the format selector
* #private
*/
createFormatOptions: function() {
var htmlCode = "";
if (this.formats) {
var formatCnt = this.formats.length;
htmlCode += "<option value='none'>None</option>";
for (var f = 0; f < formatCnt; f++) {
var text = this.formats[f].text;
htmlCode += "<option value=\"" + this.formats[f].value + "\">" + text
+ "</option>";
}
}
return htmlCode;
},
createToolbarDef: function() {
return {
"xtype": "panel",
"itemId": this.id,
"html": "<select class=\"x-placeholder-select\">"
+ this.createFormatOptions() + "</select>",
"listeners": {
"afterrender": function() {
var item = this.toolbar.items.get(this.id);
if (item && item.body) {
this.formatSelector = CQ.Ext.get(item.body.dom.childNodes[0]);
this.initializeSelector();
}
},
"scope": this
}
};
},
initializeSelector: function() {
this.formatSelector.on('change', function() {
var format = this.formatSelector.dom.value;
if (format.length > 0) {
this.plugin.execute(this.id);
}
}, this);
this.formatSelector.on('focus', function() {
this.plugin.editorKernel.isTemporaryBlur = true;
}, this);
// fix for a Firefox problem that adjusts the combobox' height to the height
// of the largest entry
this.formatSelector.setHeight(20);
},
getSelectorDom: function() {
return this.formatSelector.dom;
},
getSelectedFormat: function() {
var format;
if (this.formatSelector) {
format = this.formatSelector.dom.value;
if (format.length > 0) {
return format;
}
} else {
var item = this.toolbar.items.get(this.id);
if (item.getValue()) {
return item;
}
}
return null;
},
selectFormat: function(formatToSelect, auxRoot, formatCnt, noFormatCnt) {
var indexToSelect = -1;
var selectorDom = this.formatSelector.dom;
if ((formatToSelect != null) && (formatCnt == 1) && (noFormatCnt == 0)) {
var options = selectorDom.options;
for (var optIndex = 0; optIndex < options.length; optIndex++) {
var optionToCheck = options[optIndex];
if (optionToCheck.value == formatToSelect) {
indexToSelect = optIndex;
break;
}
}
}
selectorDom.disabled = (noFormatCnt > 0) && (auxRoot == null);
selectorDom.selectedIndex = indexToSelect;
}
});
I have a list of div's all with a set and equal height/width that are float:left so they sit next to each other and fold under if that parent is smaller than the combined with of the items.
Pretty standard.
This is to create a list of the twitter bootstrap icons, it gives something like this:
I have added next/previous keyboard navigation using the code below, however you will notice that the up/down arrow keys are mapped to call the left/right functions. What I have no idea how to do is to actually do the up/down navigation?
JsFiddle
(function ($) {
$.widget("ui.iconSelect", {
// default options
options: {
},
$select: null,
$wrapper: null,
$list: null,
$filter: null,
$active: null,
icons: {},
keys: {
left: 37,
up: 38,
right: 39,
down: 40
},
//initialization function
_create: function () {
var that = this;
that.$select = that.element;
that.$wrapper = $('<div class="select-icon" tabindex="0"></div>');
that.$filter = $('<input class="span12" tabindex="-1" placeholder="Filter by class name..."/>').appendTo(that.$wrapper);
that.$list = $('<div class="select-icon-list"></div>').appendTo(that.$wrapper);
//build the list of icons
that.element.find('option').each(function () {
var $option = $(this);
var icon = $option.val();
that.icons[icon] = $('<a data-class="' + icon + '"><i class="icon ' + icon + '"></i></a>');
if ($option.is(':selected')) {
that.icons[icon].addClass('selected active');
}
that.$list.append(that.icons[icon]);
});
that.$wrapper.insertBefore(that.$select);
that.$select.addClass('hide');
that._setupArrowKeysHandler();
that._setupClickHandler();
that._setupFilter();
that.focus('selected');
},
focus: function (type) {
var that = this;
if (that.$active === null || that.$active.length == 0) {
if (type == 'first') {
that.$active = that.$list.find('a:visible:first');
} else if (type == 'last') {
that.$active = that.$list.find('a:visible:last');
} else if (type == 'selected') {
that.$active = that.$list.find('a.selected:visible:first');
that.focus('first');
}
}
that.$active.addClass('active');
var toScroll = ((that.$list.scrollTop() + that.$active.position().top)-that.$list.height()/2)+that.$active.height()/2;
//that.$list.scrollTop((that.$list.scrollTop() + top)-that.$list.height()/2);
that.$list.stop(true).animate({
scrollTop: toScroll,
queue: false,
easing: 'linear'
}, 200);
if (type === 'selected') {
return false;
}
that.$select.val(that.$active.data('class'));
that.$select.trigger('change');
},
_setupArrowKeysHandler: function () {
var that = this;
that.$wrapper.on('keydown', function (e) {
switch (e.which) {
case that.keys.left:
that.moveLeft();
break;
case that.keys.up:
that.moveUp();
break;
case that.keys.right:
that.moveRight();
break;
case that.keys.down:
that.moveDown();
break;
case 16:
return true;
case 9:
return true;
break;
default:
that.$filter.focus();
return true;
}
return false;
});
},
_setupFilter: function(){
var that = this;
that.$filter.on('keydown keyup keypress paste cut change', function(e){
that.filter(that.$filter.val());
});
},
_setupClickHandler: function () {
var that = this;
that.$list.on('click', 'a', function () {
that.$wrapper.focus();
that.$active.removeClass('active');
that.$active = $(this);
that.focus('first');
});
},
moveUp: function () {
var that = this;
return that.moveLeft();
},
moveDown: function () {
var that = this;
return that.moveRight();
},
moveLeft: function () {
var that = this;
that.$active.removeClass('active');
that.$active = that.$active.prevAll(':visible:first');
that.focus('last');
return false;
},
moveRight: function () {
var that = this;
that.$active.removeClass('active');
that.$active = that.$active.nextAll(':visible:first');
that.focus('first');
return false;
},
filter: function(word){
var that = this;
var regexp = new RegExp(word.toLowerCase());
var found = false;
$.each(that.icons, function(i, $v){
found = regexp.test(i);
if(found && !$v.is(':visible')){
$v.show();
} else if(!found && $v.is(':visible')){
$v.hide();
}
});
}
});
})(jQuery);
Perhaps something like this: http://jsfiddle.net/QFzCY/
var blocksPerRow = 4;
$("body").on("keydown", function(e){
var thisIndex = $(".selected").index();
var newIndex = null;
if(e.keyCode === 38) {
// up
newIndex = thisIndex - blocksPerRow;
}
else if(e.keyCode === 40) {
// down
newIndex = thisIndex + blocksPerRow;
}
if(newIndex !== null) {
$(".test").eq(newIndex).addClass("selected").siblings().removeClass("selected");
}
});
Basically, you set how many items there are in a row and then find the current index and subtract or add that amount to select the next element via the new index.
If you need to know how many blocks per row there are, you could do this:
var offset = null;
var blocksPerRow = 0;
$(".test").each(function(){
if(offset === null) {
offset = $(this).offset().top;
}
else if($(this).offset().top !== offset) {
return false;
}
blocksPerRow++;
});
To deal with your 'edge' cases, you could do:
if(newIndex >= $(".test").length) {
newIndex = $(".test").length - newIndex;
}
moveUp: function () {
var that = this;
var index = $(this).index();
var containerWidth = parseInt( $('.select-icon-list').innerWidth(), 10);
var iconWidth = parseInt( $('.select-icon-list > a').width(), 10);
var noOfCols = Math.floor( containerWidth / iconWidth );
var newIndex = ( (index - noOfCols) < 0 ) ? index : (index - noOfCols);
var elem = $('.select-icon-list > a')[index];
},
Cache what ever remains static.
Can somebody recommend an easy to use Lightbox plug-in for ExtJS 4?
The best I can do at the momemnt is http://dev.sencha.com/playpen/ext-core-latest/examples/lightbox/. This relates to ExtJS 3 and I cannot find an equivalent in ExtJS 4.
I found adapted version for ExtJS4 here .
/*!
* Based on the lightbox implementation in Ext Core Library 3.0
* http://www.lyquidity.com/
* Copyright(c) 2012, Lyquidity Solutions Limited.
*
* MIT Licensed - http://extjs.com/license/mit.txt
*/
Ext.define('Ext.ux.Lightbox', {
extend: 'Ext.Component',
alias: 'widget.lightbox',
id: 'ux-lightbox',
/**
* #cfg {int} activeImage The index of the current image.
*/
activeImage: undefined,
/**
* #cfg {boolean} animate True if the image change transition is to be animated.
*/
animate: true,
/**
* #cfg {int} borderSize The size of the image border.
*/
borderSize: 10,
/**
* #cfg {string} labelImage The term for 'image'.
*/
labelImage: "Image",
/**
* #cfg {string} labelOf The term for 'of' as in '3 of 7'.
*/
labelOf: "of",
/**
* #cfg {int} overlayOpacity The relativ opacity of the overlay (background). Default: 0.85.
*/
overlayOpacity: 0.85,
/**
* #cfg {HtmlElement} renderTo The element to which the lightbox will be rendered. Defaults to the body.
*/
renderTo: Ext.getBody(),
/**
* #cfg {int} resizeSpeed Time in milliseconds for the lightbox to resize to a new image. Default: 600ms.
*/
resizeSpeed: 600,
/**
* #cfg {string} containerTag The tag which contains the <img> tag. Default: 'a'.
*/
containerTag: 'a',
/**
* #cfg {string} missingImage The image to use to represent a missing image. Default: missing.png.
*/
missingImage: 'missing.png',
childEls: ['outerImageContainer', 'imageContainer', 'image', 'hoverNav', 'navPrev', 'navNext',
'outerDataContainer', 'dataContainer', 'data', 'details', 'caption', 'imageNumber', 'bottomNav', 'navClose'],
initComponent: function()
{
var me = this;
// This weirdness is here because I'm simulating what happens in the Designer
// which has a bug because renderTpl is set to null by ExtJS so Ext.applyIf()
// has no effect. Setting renderTpl to undefined solves the problem.
// You can remove this by using Ext.apply() instead or by moving the renderTpl
// out of the initComponent function.
this.renderTpl = undefined;
Ext.applyIf(me, {
renderTpl: [
'<div id="ux-lightbox-outerImageContainer">',
' <div id="ux-lightbox-imageContainer">',
' <img id="ux-lightbox-image">',
' <div id="ux-lightbox-hoverNav">',
' ',
' ',
' </div>',
' </div>',
'</div>',
'<div id="ux-lightbox-outerDataContainer">',
' <div id="ux-lightbox-dataContainer">',
' <div id="ux-lightbox-data">',
' <div id="ux-lightbox-details">',
' <span id="ux-lightbox-caption"></span>',
' <span id="ux-lightbox-imageNumber"></span>',
' </div>',
' <div id="ux-lightbox-bottomNav">',
' ',
' </div>',
' </div>',
' </div>',
'</div>'
],
images: [],
selectors: [],
listeners: {
beforerender: {
fn: me.onComponentBeforeRender,
scope: me
},
afterrender: {
fn: me.onComponentAfterRender,
scope: me
}
}
});
this.resizeDuration = this.animate ? this.resizeSpeed : 0;
this.overlayDuration = this.animate ? 200 : 0;
this.addEvents('open', 'close');
this.callParent(arguments);
},
onComponentBeforeRender: function () {
var me = this;
this.shim = Ext.DomHelper.append( this.renderTo,
{
tag: 'iframe',
id: 'ux-lightbox-shim'
}, true);
this.overlay = Ext.DomHelper.append(this.renderTo, {
id: 'ux-lightbox-overlay'
}, true);
},
onComponentAfterRender: function (container, position) {
var me = this;
Ext.each([this.overlay, this.shim, this.el], function(el){
el.setVisibilityMode(Ext.Element.DISPLAY).hide();
});
this.setVisible(false).setPosition(0, 20);
var size = (this.animate ? 250 : 1);
this.outerImageContainer.setSize(size,size);
this.outerDataContainer.setWidth(size).hide();
// Initialize events
var close = function(ev)
{
ev.preventDefault();
this.close();
};
this.overlay.on('click', close, this);
this.navClose.on('click', close, this);
this.el.on('click', function(ev)
{
if(ev.getTarget().id == this.getId())
this.close();
}, this);
this.navPrev.on('click', function(ev)
{
ev.preventDefault();
this.setImage(this.activeImage - 1);
}, this);
this.navNext.on('click', function(ev)
{
ev.preventDefault();
this.setImage(this.activeImage + 1);
}, this);
},
/**
* Called by user to register the images to include in the lightbox
* #property register
* #type Function
* #param {String} The selector to find the images in 'container' to register
* #param {boolean} True if the images are a group
* #param {String} The container which holds the images to use. Default: body
*/
register: function(sel, group, container)
{
this.thumbnailContainer = container
? container
: Ext.getBody();
if (this.renderTo != Ext.getBody())
{
this.renderTo.setStyle({position:'relative'});
}
var selector = {sel: sel, group: group};
var length = Ext.Array.filter(this.selectors, function(item) { return item.sel === sel; }, this).length;
if(length === 0)
{
this.selectors.push(selector);
// This ability to use functions like 'on' against the result of Ext.fly() or Ext.select() is good
Ext.select(sel, true, this.thumbnailContainer.dom).on('click', this.click, this);
}
},
/**
* Private function to handle the image click event
* #property click
* #type Function
* #param {HTMLElement} ev The contained item pressed
*/
click: function(ev)
{
try
{
// Get the parent of the clicked element which is the container
var up = Ext.get(ev.target).up(this.containerTag);
var target = undefined;
var selector = undefined;
Ext.each(this.selectors, function(item)
{
var els = Ext.select(item.sel, true);
var i = els.indexOf(up);
if (i === -1) return;
target = ev.getTarget(item.sel);
selector = item;
}, true );
if (target)
{
ev.preventDefault();
this.open(target, selector.sel, selector.group);
}
}
catch (e)
{
console.log(e.message);
}
},
remove: function()
{
this.clear();
Ext.enableNestedListenerRemoval = true;
Ext.each([this.overlay, this.shim], function(node)
{
if (!node) return;
Ext.removeNode(node.dom);
delete node;
});
this.destroy();
},
/**
* Clears the click events on all registered images
* #property clear
* #type Function
*/
clear: function()
{
this.close();
if (!this.selectors) return;
Ext.each(this.selectors, function(item)
{
Ext.select(item.sel, true, this.thumbnailContainer.dom).un('click', this.click, this);
},this);
this.selectors = [];
this.images = [];
},
/**
* Called automatically when the page has completely loaded. This is an empty function that should be
* overridden by each application that needs to take action on page load
* #property launch
* #type Function
* #param {HTMLElement} image The element containing the item to display
* #param {String} sel The selector for the image
* #param {Boolean} group True if this image is part of a group
*/
open: function(image, sel, group)
{
// Close the image if on is already open
if (this.isVisible())
{
Ext.callback( this.close, this, [this.open,image, sel, group] );
return;
}
group = group || false;
this.setViewSize();
this.overlay.setTop(0);
this.overlay.setLeft(0);
this.overlay.show();
this.overlay.setOpacity(0);
this.overlay.fadeIn({
duration: this.overlayDuration,
opacity: this.overlayOpacity,
callback: function() {
this.images = [];
var index = 0;
if(!group) {
this.images.push([image.href, image.title]);
}
else {
var setItems = Ext.query(sel,this.thumbnailContainer);
Ext.each(setItems, function(item){
var href = item.href;
href = item.getAttribute('href');
if(href) {
this.images.push([href, item.title]);
}
}, this);
while (index < this.images.length && this.images[index][0] != image.getAttribute('href')) {
index++;
}
}
// calculate top and left offset for the lightbox
var pageScroll = Ext.fly(this.renderTo.dom).getScroll();
var size = this.getViewSize();
var lightboxLeft = pageScroll.left;
this.setHeight(size.height);
this.setWidth(size.width);
this.setVisible(true);
this.setImage(index);
this.fireEvent('open', index == this.images.length ? undefined : this.images[index]);
},
scope: this
});
},
setViewSize: function()
{
var viewSize = this.getViewSize();
this.overlay.setStyle({
width: viewSize.width + 'px',
height: viewSize.height + 'px'
});
this.shim.setStyle({
width: viewSize.width + 'px',
height: viewSize.height + 'px'
}).show();
},
setImage: function(index)
{
this.activeImage = index;
this.disableKeyNav();
if (this.animate)
this.showMask();
this.image.fadeOut({
duration: this.resizeDuration,
scope: this,
callback: function()
{
this.image.hide();
delete this.lastImage;
this.hoverNav.hide();
this.navPrev.hide();
this.navNext.hide();
this.dataContainer.setOpacity(0.0001);
this.imageNumber.hide();
var imageSrc = (this.activeImage >= this.images.length)
? this.missingImage
: this.images[this.activeImage][0];
this.preview = Ext.create('Ext.Img',
{
src: imageSrc,
hidden: true,
renderTo: Ext.getBody(),
listeners : {
load : {
element : 'el', //the rendered img element
fn : function()
{
this.image.dom.src = this.preview.src;
this.resizeImage(this.preview.el.dom.width, this.preview.el.dom.height);
Ext.removeNode(this.preview.el.dom);
delete this.preview;
},
scope: this
}
}
});
}
});
},
resizeImage: function(w, h)
{
this.hideMask();
var wCur = this.outerImageContainer.getWidth();
var hCur = this.outerImageContainer.getHeight();
// The w and h could exceed the displayable area so this
// should be checked and the w/h changed accordingly.
var guesstimateDetailsSize = 60;
var size = this.getViewSize();
while ((w+this.borderSize * 2 > size.width) || (h+this.borderSize * 2 + guesstimateDetailsSize > size.height))
{
if (w+this.borderSize * 2 > size.width)
{
// Compute the new width
var wtemp = size.width - this.borderSize * 2;
// Compute the corresponding height so the aspect ratio remains the same
var htemp = Math.abs(wtemp/w*h);
w = wtemp;
h = htemp;
}
if (h+this.borderSize * 2 + guesstimateDetailsSize > size.height)
{
// Compute the new height
var htemp = size.height - guesstimateDetailsSize - this.borderSize * 2;
// Compute the corresponding width so the aspect ratio remains the same
var wtemp = Math.abs(htemp/h*w);
w = wtemp;
h = htemp;
}
}
var wNew = (w + this.borderSize * 2);
var hNew = (h + this.borderSize * 2);
var wDiff = wCur - wNew;
var hDiff = hCur - hNew;
var afterResize = function(){
this.hoverNav.setWidth(this.imageContainer.getWidth() + 'px');
this.navPrev.setHeight(h + 'px');
this.navNext.setHeight(h + 'px');
this.outerDataContainer.setWidth(wNew + 'px');
this.outerDataContainer.show();
this.showImage(w,h);
};
if (hDiff != 0 || wDiff != 0)
{
this.outerImageContainer.animate(
{
height: hNew,
width: wNew,
duration: this.resizeDuration,
scope: this,
callback: afterResize,
delay: 50
});
}
else
{
afterResize.call(this);
}
},
hideMask: function()
{
if (Ext.getVersion().major === 4 && Ext.getVersion().minor === 0)
{
if (!this.mask) return
this.mask.hide();
}
else
this.imageContainer.unmask();
},
showMask: function()
{
if (Ext.getVersion().major === 4 && Ext.getVersion().minor === 0)
{
if (!this.mask)
{
this.mask = new Ext.LoadMask(this.imageContainer, {});
}
this.mask.show();
}
else
this.imageContainer.mask('Loading image...');
},
showImage: function(w,h)
{
// Is it already displayed?
if (this.lastImage && this.lastImage == this.image.dom.src)
return;
this.lastImage = this.image.dom.src;
this.image.setWidth(w);
this.image.setHeight(h);
this.image.setOpacity(0);
this.image.show({
duration: this.resizeDuration,
scope: this,
callback: this.updateDetails()
});
this.preloadImages();
},
updateDetails: function()
{
var detailsWidth = this.data.getWidth(true) - this.navClose.getWidth() - 10;
this.details.setWidth((detailsWidth > 0 ? detailsWidth : 0) + 'px');
this.caption.update((this.activeImage >= this.images.length) ? '' : this.images[this.activeImage][1]);
this.caption.show();
if (this.images.length > 1) {
this.imageNumber.update(this.labelImage + ' ' + (this.activeImage + 1) + ' ' + this.labelOf + ' ' + this.images.length);
this.imageNumber.show();
}
this.dataContainer.fadeIn({
duration: this.resizeDuration/2,
scope: this,
callback: function() {
var viewSize = this.getViewSize();
this.overlay.setHeight(viewSize.height + 'px');
var total = this.outerDataContainer.getHeight() + this.outerImageContainer.getHeight();
this.setHeight(total);
var position = this.getPosition(true);
var distance = Math.abs((this.getViewSize().height - total)/2) - position[1];
this.el.move("b", distance, {
duration: this.resizeDuration,
scope: this,
callback: this.updateNav()
});
}
});
},
updateNav: function()
{
this.enableKeyNav();
this.hoverNav.show();
// if not first image in set, display prev image button
if (this.activeImage > 0)
this.navPrev.show();
// if not last image in set, display next image button
if (this.activeImage < (this.images.length - 1))
this.navNext.show();
},
enableKeyNav: function()
{
Ext.fly(this.renderTo.dom).on('keydown', this.keyNavAction, this);
},
disableKeyNav: function()
{
Ext.fly(this.renderTo.dom).un('keydown', this.keyNavAction, this);
},
keyNavAction: function(ev)
{
var keyCode = ev.getKey();
if (
keyCode == 88 || // x
keyCode == 67 || // c
keyCode == 27
) {
this.close();
}
else if (keyCode == 80 || keyCode == 37){ // display previous image
if (this.activeImage != 0){
this.setImage(this.activeImage - 1);
}
}
else if (keyCode == 78 || keyCode == 39){ // display next image
if (this.activeImage != (this.images.length - 1)){
this.setImage(this.activeImage + 1);
}
}
},
preloadImages: function()
{
var next, prev;
if (this.images.length > this.activeImage + 1)
{
next = new Image();
next.src = this.images[this.activeImage + 1][0];
}
if (this.activeImage > 0)
{
prev = new Image();
prev.src = this.images[this.activeImage - 1][0];
}
},
close: function(callback,image, sel, group)
{
if (!this.isVisible()) return;
this.hideMask();
this.disableKeyNav();
this.setVisible(false);
this.shim.hide();
this.overlay.fadeOut({
duration: this.overlayDuration,
stopAnimation: true,
scope: this,
callback: function()
{
if (this.overlay)
this.overlay.hide();
if (callback)
Ext.callback(callback, this, [image, sel, group], 1);
}
});
this.fireEvent('close', this.activeImage);
},
getViewSize: function()
{
return {width: this.renderTo.getWidth(), height: this.renderTo.getHeight()};
}
});
I'm not able to leave a comment, but some people on the Sencha forums have already tried to build off the example you linked to: http://www.sencha.com/forum/showthread.php?138296-Ext.ux.Lightbox
I think your best bet is to build off their existing work to adapt it for Ext 4.