You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by ed...@apache.org on 2006/11/11 17:44:48 UTC
svn commit: r473755 [28/43] - in /jackrabbit/trunk/contrib/jcr-browser: ./
src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/
src/main/java/org/apache/jackrabbit/
src/main/java/org/apache/jackrabbit/browser/ src/main/resources/ ...
Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DomWidget.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DomWidget.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DomWidget.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DomWidget.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,892 @@
+dojo.provide("dojo.widget.DomWidget");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.Widget");
+dojo.require("dojo.dom");
+dojo.require("dojo.html.style");
+dojo.require("dojo.xml.Parse");
+dojo.require("dojo.uri.*");
+dojo.require("dojo.lang.func");
+dojo.require("dojo.lang.extras");
+
+dojo.widget._cssFiles = {};
+dojo.widget._cssStrings = {};
+dojo.widget._templateCache = {};
+
+// Object: a mapping of strings that are used in template variable replacement
+dojo.widget.defaultStrings = {
+ dojoRoot: dojo.hostenv.getBaseScriptUri(),
+ baseScriptUri: dojo.hostenv.getBaseScriptUri()
+};
+
+dojo.widget.fillFromTemplateCache = function( /*DomWidget*/ obj,
+ /*String||dojo.uri.Uri*/ templatePath,
+ /*String, optional*/ templateString,
+ /*Boolean, optional*/ avoidCache){
+ // summary:
+ // static method to build from a template w/ or w/o a real widget in
+ // place
+ // obj: an instance of dojo.widget.DomWidget to initialize the template for
+ // templatePath: the URL to get the template from
+ // templateString:
+ // a string to use in lieu of fetching the template from a URL
+ // avoidCache:
+ // should the template system not use whatever is in the cache and
+ // always use the passed templatePath or templateString?
+
+ // dojo.debug("avoidCache:", avoidCache);
+ var tpath = templatePath || obj.templatePath;
+
+ var tmplts = dojo.widget._templateCache;
+ if(!obj["widgetType"]) { // don't have a real template here
+ do {
+ var dummyName = "__dummyTemplate__" + dojo.widget._templateCache.dummyCount++;
+ } while(tmplts[dummyName]);
+ obj.widgetType = dummyName;
+ }
+ var wt = obj.widgetType;
+
+ var ts = tmplts[wt];
+ if(!ts){
+ tmplts[wt] = { "string": null, "node": null };
+ if(avoidCache){
+ ts = {};
+ }else{
+ ts = tmplts[wt];
+ }
+ }
+ if((!obj.templateString)&&(!avoidCache)){
+ obj.templateString = templateString || ts["string"];
+ }
+ if((!obj.templateNode)&&(!avoidCache)){
+ obj.templateNode = ts["node"];
+ }
+ if((!obj.templateNode)&&(!obj.templateString)&&(tpath)){
+ // fetch a text fragment and assign it to templateString
+ // NOTE: we rely on blocking IO here!
+ var tstring = dojo.hostenv.getText(tpath);
+ if(tstring){
+ // strip <?xml ...?> declarations so that external SVG and XML
+ // documents can be added to a document without worry
+ tstring = tstring.replace(/^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, "");
+ var matches = tstring.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+ if(matches){
+ tstring = matches[1];
+ }
+ }else{
+ tstring = "";
+ }
+ obj.templateString = tstring;
+ if(!avoidCache){
+ tmplts[wt]["string"] = tstring;
+ }
+ }
+ if((!ts["string"])&&(!avoidCache)){
+ ts.string = obj.templateString;
+ }
+}
+dojo.widget._templateCache.dummyCount = 0;
+
+// Array: list of properties to search for node-to-property mappings
+dojo.widget.attachProperties = ["dojoAttachPoint", "id"];
+// String: name of the property to use for mapping DOM events to widget functions
+dojo.widget.eventAttachProperty = "dojoAttachEvent";
+// String: property name of code to evaluate when the widget is constructed
+dojo.widget.onBuildProperty = "dojoOnBuild";
+// Array: possible accessibility values to set on widget elements - role or state
+dojo.widget.waiNames = ["waiRole", "waiState"];
+// Object: Contains functions to set accessibility roles and states
+// onto widget elements
+dojo.widget.wai = {
+ waiRole: {
+ // String: information for mapping accessibility role
+ name: "waiRole",
+ // String: URI of the namespace for the set of roles
+ "namespace": "http://www.w3.org/TR/xhtml2",
+ // String: alias to assign the namespace
+ alias: "x2",
+ // String: prefix to assign to the role value
+ prefix: "wairole:"
+ },
+ waiState: {
+ // String: informatin for mapping accessibility state
+ name: "waiState",
+ // String: URI of the namespace for the set of states
+ "namespace": "http://www.w3.org/2005/07/aaa",
+ // String: alias to assign the namespace
+ alias: "aaa",
+ // String: empty string - state value does not require prefix
+ prefix: ""
+ },
+ setAttr: function(/*DomNode*/node, /*String*/ ns, /*String*/ attr, /*String|Boolean*/value){
+ // Summary: Use appropriate API to set the role or state attribute onto the element.
+ // Description: In IE use the generic setAttribute() api. Append a namespace
+ // alias to the attribute name and appropriate prefix to the value.
+ // Otherwise, use the setAttribueNS api to set the namespaced attribute. Also
+ // add the appropriate prefix to the attribute value.
+ if(dojo.render.html.ie){
+ node.setAttribute(this[ns].alias+":"+ attr, this[ns].prefix+value);
+ }else{
+ node.setAttributeNS(this[ns]["namespace"], attr, this[ns].prefix+value);
+ }
+ },
+
+ getAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+ // Summary: Use the appropriate API to retrieve the role or state value
+ // Description: In IE use the generic getAttribute() api. An alias value
+ // was added to the attribute name to simulate a namespace when the attribute
+ // was set. Otherwise use the getAttributeNS() api to retrieve the state value
+ if(dojo.render.html.ie){
+ return node.getAttribute(this[ns].alias+":"+attr);
+ }else{
+ return node.getAttributeNS(this[ns]["namespace"], attr);
+ }
+ },
+ removeAttr: function(/*DomNode*/ node, /*String*/ ns, /*String|Boolena*/ attr){
+ // Summary: Use the appropriate API to remove the role or state value
+ // Description: In IE use the generic removeAttribute() api. An alias value
+ // was added to the attribute name to simulate a namespace when the attribute
+ // was set. Otherwise use the removeAttributeNS() api to remove the state value
+ var success = true; //only IE returns a value
+ if(dojo.render.html.ie){
+ success = node.removeAttribute(this[ns].alias+":"+attr);
+ }else{
+ node.removeAttributeNS(this[ns]["namespace"], attr);
+ }
+ return success;
+ }
+};
+
+dojo.widget.attachTemplateNodes = function( /*DomNode*/ rootNode,
+ /*Widget*/ targetObj,
+ /*Array*/ events ){
+ // summary:
+ // map widget properties and functions to the handlers specified in
+ // the dom node and it's descendants. This function iterates over all
+ // nodes and looks for these properties:
+ // * dojoAttachPoint
+ // * dojoAttachEvent
+ // * waiRole
+ // * waiState
+ // * any "dojoOn*" proprties passed in the events array
+ // rootNode:
+ // the node to search for properties. All children will be searched.
+ // events: a list of properties generated from getDojoEventsFromStr.
+
+ // FIXME: this method is still taking WAAAY too long. We need ways of optimizing:
+ // a.) what we are looking for on each node
+ // b.) the nodes that are subject to interrogation (use xpath instead?)
+ // c.) how expensive event assignment is (less eval(), more connect())
+ // var start = new Date();
+ var elementNodeType = dojo.dom.ELEMENT_NODE;
+
+ function trim(str){
+ return str.replace(/^\s+|\s+$/g, "");
+ }
+
+ if(!rootNode){
+ rootNode = targetObj.domNode;
+ }
+
+ if(rootNode.nodeType != elementNodeType){
+ return;
+ }
+ // alert(events.length);
+
+ var nodes = rootNode.all || rootNode.getElementsByTagName("*");
+ var _this = targetObj;
+ for(var x=-1; x<nodes.length; x++){
+ var baseNode = (x == -1) ? rootNode : nodes[x];
+ // FIXME: is this going to have capitalization problems? Could use getAttribute(name, 0); to get attributes case-insensitve
+ var attachPoint = [];
+ if(!targetObj.widgetsInTemplate || !baseNode.getAttribute('dojoType')){
+ for(var y=0; y<this.attachProperties.length; y++){
+ var tmpAttachPoint = baseNode.getAttribute(this.attachProperties[y]);
+ if(tmpAttachPoint){
+ attachPoint = tmpAttachPoint.split(";");
+ for(var z=0; z<attachPoint.length; z++){
+ if(dojo.lang.isArray(targetObj[attachPoint[z]])){
+ targetObj[attachPoint[z]].push(baseNode);
+ }else{
+ targetObj[attachPoint[z]]=baseNode;
+ }
+ }
+ break;
+ }
+ }
+
+ var attachEvent = baseNode.getAttribute(this.eventAttachProperty);
+ if(attachEvent){
+ // NOTE: we want to support attributes that have the form
+ // "domEvent: nativeEvent; ..."
+ var evts = attachEvent.split(";");
+ for(var y=0; y<evts.length; y++){
+ if((!evts[y])||(!evts[y].length)){ continue; }
+ var thisFunc = null;
+ var tevt = trim(evts[y]);
+ if(evts[y].indexOf(":") >= 0){
+ // oh, if only JS had tuple assignment
+ var funcNameArr = tevt.split(":");
+ tevt = trim(funcNameArr[0]);
+ thisFunc = trim(funcNameArr[1]);
+ }
+ if(!thisFunc){
+ thisFunc = tevt;
+ }
+
+ var tf = function(){
+ var ntf = new String(thisFunc);
+ return function(evt){
+ if(_this[ntf]){
+ _this[ntf](dojo.event.browser.fixEvent(evt, this));
+ }
+ };
+ }();
+ dojo.event.browser.addListener(baseNode, tevt, tf, false, true);
+ // dojo.event.browser.addListener(baseNode, tevt, dojo.lang.hitch(_this, thisFunc));
+ }
+ }
+
+ for(var y=0; y<events.length; y++){
+ //alert(events[x]);
+ var evtVal = baseNode.getAttribute(events[y]);
+ if((evtVal)&&(evtVal.length)){
+ var thisFunc = null;
+ var domEvt = events[y].substr(4); // clober the "dojo" prefix
+ thisFunc = trim(evtVal);
+ var funcs = [thisFunc];
+ if(thisFunc.indexOf(";")>=0){
+ funcs = dojo.lang.map(thisFunc.split(";"), trim);
+ }
+ for(var z=0; z<funcs.length; z++){
+ if(!funcs[z].length){ continue; }
+ var tf = function(){
+ var ntf = new String(funcs[z]);
+ return function(evt){
+ if(_this[ntf]){
+ _this[ntf](dojo.event.browser.fixEvent(evt, this));
+ }
+ }
+ }();
+ dojo.event.browser.addListener(baseNode, domEvt, tf, false, true);
+ // dojo.event.browser.addListener(baseNode, domEvt, dojo.lang.hitch(_this, funcs[z]));
+ }
+ }
+ }
+ }
+ // continue;
+
+ // FIXME: we need to put this into some kind of lookup structure
+ // instead of direct assignment
+ var tmpltPoint = baseNode.getAttribute(this.templateProperty);
+ if(tmpltPoint){
+ targetObj[tmpltPoint]=baseNode;
+ }
+
+ dojo.lang.forEach(dojo.widget.waiNames, function(name){
+ var wai = dojo.widget.wai[name];
+ var val = baseNode.getAttribute(wai.name);
+ if(val){
+ if(val.indexOf('-') == -1){
+ dojo.widget.wai.setAttr(baseNode, wai.name, "role", val);
+ }else{
+ // this is a state-value pair
+ var statePair = val.split('-');
+ dojo.widget.wai.setAttr(baseNode, wai.name, statePair[0], statePair[1]);
+ }
+ }
+ }, this);
+
+ var onBuild = baseNode.getAttribute(this.onBuildProperty);
+ if(onBuild){
+ eval("var node = baseNode; var widget = targetObj; "+onBuild);
+ }
+ }
+
+}
+
+dojo.widget.getDojoEventsFromStr = function(/*String*/str){
+ // summary:
+ // generates a list of properties with names that match the form
+ // dojoOn*
+ // str: the template string to search
+
+ // var lstr = str.toLowerCase();
+ var re = /(dojoOn([a-z]+)(\s?))=/gi;
+ var evts = str ? str.match(re)||[] : [];
+ var ret = [];
+ var lem = {};
+ for(var x=0; x<evts.length; x++){
+ if(evts[x].length < 1){ continue; }
+ var cm = evts[x].replace(/\s/, "");
+ cm = (cm.slice(0, cm.length-1));
+ if(!lem[cm]){
+ lem[cm] = true;
+ ret.push(cm);
+ }
+ }
+ return ret; // Array
+}
+
+/*
+dojo.widget.buildAndAttachTemplate = function(obj, templatePath, templateCssPath, templateString, targetObj) {
+ this.buildFromTemplate(obj, templatePath, templateCssPath, templateString);
+ var node = dojo.dom.createNodesFromText(obj.templateString, true)[0];
+ this.attachTemplateNodes(node, targetObj||obj, dojo.widget.getDojoEventsFromStr(templateString));
+ return node;
+}
+*/
+
+
+// summary:
+// dojo.widget.DomWidget is the superclass that provides behavior for all
+// DOM-based renderers, including HtmlWidget and SvgWidget. DomWidget
+// implements the templating system that most widget authors use to define
+// the UI for their widgets.
+dojo.declare("dojo.widget.DomWidget",
+ dojo.widget.Widget,
+ function(){
+ if((arguments.length>0)&&(typeof arguments[0] == "object")){
+ this.create(arguments[0]);
+ }
+ },
+ {
+ // DomNode: a node that represents the widget template. Pre-empts both templateString and templatePath.
+ templateNode: null,
+
+ // String:
+ // a string that represents the widget template. Pre-empts the
+ // templatePath. In builds that have their strings "interned", the
+ // templatePath is converted to an inline templateString, thereby
+ // preventing a synchronous network call.
+ templateString: null,
+
+ // String:
+ // a string that represents the CSS for the widgettemplate.
+ // Pre-empts the templateCssPath. In builds that have their
+ // strings "interned", the templateCssPath is converted to an
+ // inline templateCssString, thereby preventing a synchronous
+ // network call.
+ templateCssString: null,
+
+ // Boolean:
+ // should the widget not replace the node from which it was
+ // constructed? Widgets that apply behaviors to pre-existing parts
+ // of a page can be implemented easily by setting this to "true".
+ // In these cases, the domNode property will point to the node
+ // which the widget was created from.
+ preventClobber: false,
+
+ // DomNode:
+ // this is our visible representation of the widget! Other DOM
+ // Nodes may by assigned to other properties, usually through the
+ // template system's dojoAttachPonit syntax, but the domNode
+ // property is the canonical "top level" node in widget UI.
+ domNode: null,
+
+ // DomNode:
+ // holds child elements. "containerNode" is generally set via a
+ // dojoAttachPoint assignment and it designates where widgets that
+ // are defined as "children" of the parent will be placed
+ // visually.
+ containerNode: null,
+
+ // Boolean:
+ // should we parse the template to find widgets that might be
+ // declared in markup inside it? false by default.
+ widgetsInTemplate: false,
+
+ addChild: function( /*Widget*/ widget,
+ /*DomNode, optional*/ overrideContainerNode,
+ /*String, optional*/ pos,
+ /*DomNode, optional*/ ref,
+ /*int, optional*/ insertIndex){
+ // summary:
+ // Process the given child widget, inserting it's dom node as
+ // a child of our dom node
+ // overrideContainerNode: a non-default container node for the widget
+ // pos:
+ // can be one of "before", "after", "first", or "last". This
+ // has the same meaning as in dojo.dom.insertAtPosition()
+ // ref: a node to place the widget relative to
+ // insertIndex: DOM index, same meaning as in dojo.dom.insertAtIndex()
+
+ // FIXME: should we support addition at an index in the children arr and
+ // order the display accordingly? Right now we always append.
+ if(!this.isContainer){ // we aren't allowed to contain other widgets, it seems
+ dojo.debug("dojo.widget.DomWidget.addChild() attempted on non-container widget");
+ return null;
+ }else{
+ if(insertIndex == undefined){
+ insertIndex = this.children.length;
+ }
+ this.addWidgetAsDirectChild(widget, overrideContainerNode, pos, ref, insertIndex);
+ this.registerChild(widget, insertIndex);
+ }
+ return widget; // Widget: the widget that was inserted
+ },
+
+ addWidgetAsDirectChild: function( /*Widget*/ widget,
+ /*DomNode*/ overrideContainerNode,
+ /*String, optional*/ pos,
+ /*DomNode, optional*/ ref,
+ /*int, optional*/ insertIndex){
+ // summary:
+ // Process the given child widget, inserting it's dom node as
+ // a child of our dom node
+ // overrideContainerNode: a non-default container node for the widget
+ // pos:
+ // can be one of "before", "after", "first", or "last". This
+ // has the same meaning as in dojo.dom.insertAtPosition()
+ // ref: a node to place the widget relative to
+ // insertIndex: DOM index, same meaning as in dojo.dom.insertAtIndex()
+ if((!this.containerNode)&&(!overrideContainerNode)){
+ this.containerNode = this.domNode;
+ }
+ var cn = (overrideContainerNode) ? overrideContainerNode : this.containerNode;
+ if(!pos){ pos = "after"; }
+ if(!ref){
+ if(!cn){ cn = dojo.body(); }
+ ref = cn.lastChild;
+ }
+ if(!insertIndex) { insertIndex = 0; }
+ widget.domNode.setAttribute("dojoinsertionindex", insertIndex);
+
+ // insert the child widget domNode directly underneath my domNode, in the
+ // specified position (by default, append to end)
+ if(!ref){
+ cn.appendChild(widget.domNode);
+ }else{
+ // FIXME: was this meant to be the (ugly hack) way to support insert @ index?
+ //dojo.dom[pos](widget.domNode, ref, insertIndex);
+
+ // CAL: this appears to be the intended way to insert a node at a given position...
+ if (pos == 'insertAtIndex'){
+ // dojo.debug("idx:", insertIndex, "isLast:", ref === cn.lastChild);
+ dojo.dom.insertAtIndex(widget.domNode, ref.parentNode, insertIndex);
+ }else{
+ // dojo.debug("pos:", pos, "isLast:", ref === cn.lastChild);
+ if((pos == "after")&&(ref === cn.lastChild)){
+ cn.appendChild(widget.domNode);
+ }else{
+ dojo.dom.insertAtPosition(widget.domNode, cn, pos);
+ }
+ }
+ }
+ },
+
+ registerChild: function(/*Widget*/widget, /*int*/insertionIndex){
+ // summary: record that given widget descends from me
+ // widget: the widget that is now a child
+ // inesrtionIndex: where in the children[] array to place it
+
+ // we need to insert the child at the right point in the parent's
+ // 'children' array, based on the insertionIndex
+
+ widget.dojoInsertionIndex = insertionIndex;
+
+ var idx = -1;
+ for(var i=0; i<this.children.length; i++){
+
+ //This appears to fix an out of order issue in the case of mixed
+ //markup and programmatically added children. Previously, if a child
+ //existed from markup, and another child was addChild()d without specifying
+ //any additional parameters, it would end up first in the list, when in fact
+ //it should be after. I can't see cases where this would break things, but
+ //I could see no other obvious solution. -dustin
+
+ if (this.children[i].dojoInsertionIndex <= insertionIndex){
+ idx = i;
+ }
+ }
+
+ this.children.splice(idx+1, 0, widget);
+
+ widget.parent = this;
+ widget.addedTo(this, idx+1);
+
+ // If this widget was created programatically, then it was erroneously added
+ // to dojo.widget.manager.topWidgets. Fix that here.
+ delete dojo.widget.manager.topWidgets[widget.widgetId];
+ },
+
+ removeChild: function(/*Widget*/widget){
+ // summary: detach child domNode from parent domNode
+ dojo.dom.removeNode(widget.domNode);
+
+ // remove child widget from parent widget
+ return dojo.widget.DomWidget.superclass.removeChild.call(this, widget); // Widget
+ },
+
+ getFragNodeRef: function(/*Object*/frag){
+ // summary:
+ // returns the source node, if any, that the widget was
+ // declared from
+ // frag:
+ // an opaque data structure generated by the first-pass parser
+ if(!frag){return null;} // null
+ if(!frag[this.getNamespacedType()]){
+ dojo.raise("Error: no frag for widget type " + this.getNamespacedType()
+ + ", id " + this.widgetId
+ + " (maybe a widget has set it's type incorrectly)");
+ }
+ return frag[this.getNamespacedType()]["nodeRef"]; // DomNode
+ },
+
+ postInitialize: function(/*Object*/args, /*Object*/frag, /*Widget*/parentComp){
+ // summary:
+ // Replace the source domNode with the generated dom
+ // structure, and register the widget with its parent.
+ // This is an implementation of the stub function defined in
+ // dojo.widget.Widget.
+
+ //dojo.profile.start(this.widgetType + " postInitialize");
+
+ var sourceNodeRef = this.getFragNodeRef(frag);
+ // Stick my generated dom into the output tree
+ //alert(this.widgetId + ": replacing " + sourceNodeRef + " with " + this.domNode.innerHTML);
+ if (parentComp && (parentComp.snarfChildDomOutput || !sourceNodeRef)){
+ // Add my generated dom as a direct child of my parent widget
+ // This is important for generated widgets, and also cases where I am generating an
+ // <li> node that can't be inserted back into the original DOM tree
+ parentComp.addWidgetAsDirectChild(this, "", "insertAtIndex", "", args["dojoinsertionindex"], sourceNodeRef);
+ } else if (sourceNodeRef){
+ // Do in-place replacement of the my source node with my generated dom
+ if(this.domNode && (this.domNode !== sourceNodeRef)){
+ var oldNode = sourceNodeRef.parentNode.replaceChild(this.domNode, sourceNodeRef);
+ }
+ }
+
+ // Register myself with my parent, or with the widget manager if
+ // I have no parent
+ // TODO: the code below erroneously adds all programatically generated widgets
+ // to topWidgets (since we don't know who the parent is until after creation finishes)
+ if ( parentComp ) {
+ parentComp.registerChild(this, args.dojoinsertionindex);
+ } else {
+ dojo.widget.manager.topWidgets[this.widgetId]=this;
+ }
+
+ if(this.widgetsInTemplate){
+ var parser = new dojo.xml.Parse();
+
+ var subContainerNode;
+ //TODO: use xpath here?
+ var subnodes = this.domNode.getElementsByTagName("*");
+ for(var i=0;i<subnodes.length;i++){
+ if(subnodes[i].getAttribute('dojoAttachPoint') == 'subContainerWidget'){
+ subContainerNode = subnodes[i];
+// break;
+ }
+ if(subnodes[i].getAttribute('dojoType')){
+ subnodes[i].setAttribute('_isSubWidget', true);
+ }
+ }
+ if (this.isContainer && !this.containerNode){
+ //no containerNode is available, which means a widget is used as a container. find it here and move
+ //all dom nodes defined in the main html page as children of this.domNode into the actual container
+ //widget's node (at this point, the subwidgets defined in the template file is not parsed yet)
+ if(subContainerNode){
+ var src = this.getFragNodeRef(frag);
+ if (src){
+ dojo.dom.moveChildren(src, subContainerNode);
+ //do not need to follow children nodes in the main html page, as they
+ //will be dealt with in the subContainerWidget
+ frag['dojoDontFollow'] = true;
+ }
+ }else{
+ dojo.debug("No subContainerWidget node can be found in template file for widget "+this);
+ }
+ }
+
+ var templatefrag = parser.parseElement(this.domNode, null, true);
+ // createSubComponents not createComponents because frag has already been created
+ dojo.widget.getParser().createSubComponents(templatefrag, this);
+
+ //find all the sub widgets defined in the template file of this widget
+ var subwidgets = [];
+ var stack = [this];
+ var w;
+ while((w = stack.pop())){
+ for(var i = 0; i < w.children.length; i++){
+ var cwidget = w.children[i];
+ if(cwidget._processedSubWidgets || !cwidget.extraArgs['_issubwidget']){ continue; }
+ subwidgets.push(cwidget);
+ if(cwidget.isContainer){
+ stack.push(cwidget);
+ }
+ }
+ }
+
+ //connect event to this widget/attach dom node
+ for(var i = 0; i < subwidgets.length; i++){
+ var widget = subwidgets[i];
+ if(widget._processedSubWidgets){
+ dojo.debug("This should not happen: widget._processedSubWidgets is already true!");
+ return;
+ }
+ widget._processedSubWidgets = true;
+ if(widget.extraArgs['dojoattachevent']){
+ var evts = widget.extraArgs['dojoattachevent'].split(";");
+ for(var j=0; j<evts.length; j++){
+ var thisFunc = null;
+ var tevt = dojo.string.trim(evts[j]);
+ if(tevt.indexOf(":") >= 0){
+ // oh, if only JS had tuple assignment
+ var funcNameArr = tevt.split(":");
+ tevt = dojo.string.trim(funcNameArr[0]);
+ thisFunc = dojo.string.trim(funcNameArr[1]);
+ }
+ if(!thisFunc){
+ thisFunc = tevt;
+ }
+ if(dojo.lang.isFunction(widget[tevt])){
+ dojo.event.kwConnect({
+ srcObj: widget,
+ srcFunc: tevt,
+ targetObj: this,
+ targetFunc: thisFunc
+ });
+ }else{
+ alert(tevt+" is not a function in widget "+widget);
+ }
+ }
+ }
+
+ if(widget.extraArgs['dojoattachpoint']){
+ //don't attach widget.domNode here, as we do not know which
+ //dom node we should connect to (in checkbox widget case,
+ //it is inputNode). So we make the widget itself available
+ this[widget.extraArgs['dojoattachpoint']] = widget;
+ }
+ }
+ }
+
+ //dojo.profile.end(this.widgetType + " postInitialize");
+
+ // Expand my children widgets
+ /* dojoDontFollow is important for a very special case
+ * basically if you have a widget that you instantiate from script
+ * and that widget is a container, and it contains a reference to a parent
+ * instance, the parser will start recursively parsing until the browser
+ * complains. So the solution is to set an initialization property of
+ * dojoDontFollow: true and then it won't recurse where it shouldn't
+ */
+ if(this.isContainer && !frag["dojoDontFollow"]){
+ //alert("recurse from " + this.widgetId);
+ // build any sub-components with us as the parent
+ dojo.widget.getParser().createSubComponents(frag, this);
+ }
+ },
+
+ // method over-ride
+ buildRendering: function(/*Object*/args, /*Object*/frag){
+ // summary:
+ // Construct the UI for this widget, generally from a
+ // template. This can be over-ridden for custom UI creation to
+ // to side-step the template system. This is an
+ // implementation of the stub function defined in
+ // dojo.widget.Widget.
+
+ // DOM widgets construct themselves from a template
+ var ts = dojo.widget._templateCache[this.widgetType];
+
+ // Handle style for this widget here, as even if templatePath
+ // is not set, style specified by templateCssString or templateCssPath
+ // should be applied. templateCssString has higher priority
+ // than templateCssPath
+ if(args["templatecsspath"]){
+ args["templateCssPath"] = args["templatecsspath"];
+ }
+ var cpath = args["templateCssPath"] || this.templateCssPath;
+ if(cpath && !dojo.widget._cssFiles[cpath.toString()]){
+ if((!this.templateCssString)&&(cpath)){
+ this.templateCssString = dojo.hostenv.getText(cpath);
+ this.templateCssPath = null;
+ }
+ dojo.widget._cssFiles[cpath.toString()] = true;
+ }
+
+ if((this["templateCssString"])&&(!this.templateCssString["loaded"])){
+ dojo.html.insertCssText(this.templateCssString, null, cpath);
+ if(!this.templateCssString){ this.templateCssString = ""; }
+ this.templateCssString.loaded = true;
+ }
+ if(
+ (!this.preventClobber)&&(
+ (this.templatePath)||
+ (this.templateNode)||
+ (
+ (this["templateString"])&&(this.templateString.length)
+ )||
+ (
+ (typeof ts != "undefined")&&( (ts["string"])||(ts["node"]) )
+ )
+ )
+ ){
+ // if it looks like we can build the thing from a template, do it!
+ this.buildFromTemplate(args, frag);
+ }else{
+ // otherwise, assign the DOM node that was the source of the widget
+ // parsing to be the root node
+ this.domNode = this.getFragNodeRef(frag);
+ }
+ this.fillInTemplate(args, frag); // this is where individual widgets
+ // will handle population of data
+ // from properties, remote data
+ // sets, etc.
+ },
+
+ buildFromTemplate: function(/*Object*/args, /*Object*/frag){
+ // summary:
+ // Called by buildRendering, creates the actual UI in a DomWidget.
+
+ // var start = new Date();
+ // copy template properties if they're already set in the templates object
+ // dojo.debug("buildFromTemplate:", this);
+ var avoidCache = false;
+ if(args["templatepath"]){
+ avoidCache = true;
+ args["templatePath"] = args["templatepath"];
+ }
+ dojo.widget.fillFromTemplateCache( this,
+ args["templatePath"],
+ null,
+ avoidCache);
+ var ts = dojo.widget._templateCache[this.widgetType];
+ if((ts)&&(!avoidCache)){
+ if(!this.templateString.length){
+ this.templateString = ts["string"];
+ }
+ if(!this.templateNode){
+ this.templateNode = ts["node"];
+ }
+ }
+ var matches = false;
+ var node = null;
+ // var tstr = new String(this.templateString);
+ var tstr = this.templateString;
+ // attempt to clone a template node, if there is one
+ if((!this.templateNode)&&(this.templateString)){
+ matches = this.templateString.match(/\$\{([^\}]+)\}/g);
+ if(matches) {
+ // if we do property replacement, don't create a templateNode
+ // to clone from.
+ var hash = this.strings || {};
+ // FIXME: should this hash of default replacements be cached in
+ // templateString?
+ for(var key in dojo.widget.defaultStrings) {
+ if(dojo.lang.isUndefined(hash[key])) {
+ hash[key] = dojo.widget.defaultStrings[key];
+ }
+ }
+ // FIXME: this is a lot of string munging. Can we make it faster?
+ for(var i = 0; i < matches.length; i++) {
+ var key = matches[i];
+ key = key.substring(2, key.length-1);
+ var kval = (key.substring(0, 5) == "this.") ? dojo.lang.getObjPathValue(key.substring(5), this) : hash[key];
+ var value;
+ if((kval)||(dojo.lang.isString(kval))){
+ value = new String((dojo.lang.isFunction(kval)) ? kval.call(this, key, this.templateString) : kval);
+ // Safer substitution, see heading "Attribute values" in
+ // http://www.w3.org/TR/REC-html40/appendix/notes.html#h-B.3.2
+ while (value.indexOf("\"") > -1) {
+ value=value.replace("\"",""");
+ }
+ tstr = tstr.replace(matches[i], value);
+ }
+ }
+ }else{
+ // otherwise, we are required to instantiate a copy of the template
+ // string if one is provided.
+
+ // FIXME: need to be able to distinguish here what should be done
+ // or provide a generic interface across all DOM implementations
+ // FIMXE: this breaks if the template has whitespace as its first
+ // characters
+ // node = this.createNodesFromText(this.templateString, true);
+ // this.templateNode = node[0].cloneNode(true); // we're optimistic here
+ this.templateNode = this.createNodesFromText(this.templateString, true)[0];
+ if(!avoidCache){
+ ts.node = this.templateNode;
+ }
+ }
+ }
+ if((!this.templateNode)&&(!matches)){
+ dojo.debug("DomWidget.buildFromTemplate: could not create template");
+ return false;
+ }else if(!matches){
+ node = this.templateNode.cloneNode(true);
+ if(!node){ return false; }
+ }else{
+ node = this.createNodesFromText(tstr, true)[0];
+ }
+
+ // recurse through the node, looking for, and attaching to, our
+ // attachment points which should be defined on the template node.
+
+ this.domNode = node;
+ // dojo.profile.start("attachTemplateNodes");
+ this.attachTemplateNodes();
+ // dojo.profile.end("attachTemplateNodes");
+
+ // relocate source contents to templated container node
+ // this.containerNode must be able to receive children, or exceptions will be thrown
+ if (this.isContainer && this.containerNode){
+ var src = this.getFragNodeRef(frag);
+ if (src){
+ dojo.dom.moveChildren(src, this.containerNode);
+ }
+ }
+ },
+
+ attachTemplateNodes: function(/*DomNode*/baseNode, /*Widget*/targetObj){
+ // summary:
+ // hooks up event handlers and property/node linkages. Calls
+ // dojo.widget.attachTemplateNodes to do all the hard work.
+ // baseNode: defaults to "this.domNode"
+ // targetObj: defaults to "this"
+ if(!baseNode){ baseNode = this.domNode; }
+ if(!targetObj){ targetObj = this; }
+ return dojo.widget.attachTemplateNodes(baseNode, targetObj,
+ dojo.widget.getDojoEventsFromStr(this.templateString));
+ },
+
+ fillInTemplate: function(){
+ // summary:
+ // stub function! sub-classes may use as a default UI
+ // initializer function. The UI rendering will be available by
+ // the time this is called from buildRendering. If
+ // buildRendering is over-ridden, this function may not be
+ // fired!
+ // dojo.unimplemented("dojo.widget.DomWidget.fillInTemplate");
+ },
+
+ // method over-ride
+ destroyRendering: function(){
+ // summary: UI destructor
+ try{
+ delete this.domNode;
+ }catch(e){ /* squelch! */ }
+ },
+
+ // FIXME: method over-ride
+ cleanUp: function(){},
+
+ getContainerHeight: function(){
+ // summary: unimplemented!
+ dojo.unimplemented("dojo.widget.DomWidget.getContainerHeight");
+ },
+
+ getContainerWidth: function(){
+ // summary: unimplemented!
+ dojo.unimplemented("dojo.widget.DomWidget.getContainerWidth");
+ },
+
+ createNodesFromText: function(){
+ // summary: unimplemented!
+ dojo.unimplemented("dojo.widget.DomWidget.createNodesFromText");
+ }
+ }
+);
Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DomWidget.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownContainer.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownContainer.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownContainer.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownContainer.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,80 @@
+dojo.provide("dojo.widget.DropdownContainer");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.PopupContainer");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.html.display");
+dojo.require("dojo.html.iframe");
+dojo.require("dojo.html.util");
+
+// summary:
+// dojo.widget.DropdownContainer provides an input box and a button for a dropdown.
+// In subclass, the dropdown can be specified.
+dojo.widget.defineWidget(
+ "dojo.widget.DropdownContainer",
+ dojo.widget.HtmlWidget,
+ {
+ // String: width of the input box
+ inputWidth: "7em",
+ // String: id of this widget
+ id: "",
+ // String: id of the input box
+ inputId: "",
+ // String: name of the input box
+ inputName: "",
+ // dojo.uri.Uri: icon for the dropdown button
+ iconURL: dojo.uri.dojoUri("src/widget/templates/images/combo_box_arrow.png"),
+ // dojo.uri.Uri: alt text for the dropdown button icon
+ iconAlt: "",
+
+ inputNode: null,
+ buttonNode: null,
+ containerNode: null,
+
+ // String: toggle property of the dropdown
+ containerToggle: "plain",
+ // Int: toggle duration property of the dropdown
+ containerToggleDuration: 150,
+ containerAnimInProgress: false,
+
+ templateString: '<span style="white-space:nowrap"><input type="hidden" name="" value="" dojoAttachPoint="valueNode" /><input name="" type="text" value="" style="vertical-align:middle;" dojoAttachPoint="inputNode" autocomplete="off" /> <img src="${this.iconURL}" alt="${this.iconAlt}" dojoAttachEvent="onclick: onIconClick" dojoAttachPoint="buttonNode" style="vertical-align:middle; cursor:pointer; cursor:hand" /></span>',
+ templateCssPath: "",
+
+ fillInTemplate: function(args, frag){
+ var source = this.getFragNodeRef(frag);
+
+ this.popup = dojo.widget.createWidget("PopupContainer", {toggle: this.containerToggle, toggleDuration: this.containerToggleDuration});
+
+ this.containerNode = this.popup.domNode;
+
+ this.domNode.appendChild(this.popup.domNode);
+ if(this.id) { this.domNode.id = this.id; }
+ if(this.inputId){ this.inputNode.id = this.inputId; }
+ if(this.inputName){ this.inputNode.name = this.inputName; }
+ this.inputNode.style.width = this.inputWidth;
+
+ dojo.event.connect(this.inputNode, "onchange", this, "onInputChange");
+ },
+
+ onIconClick: function(evt){
+ if(!this.isEnabled) return;
+ if(!this.popup.isShowingNow){
+ this.popup.open(this.inputNode, this, this.buttonNode);
+ }else{
+ this.popup.close();
+ }
+ },
+
+ hideContainer: function(){
+ // summary: hide the dropdown
+ if(this.popup.isShowingNow){
+ this.popup.close();
+ }
+ },
+
+ onInputChange: function(){
+ // summary: signal for changes in the input box
+ }
+ }
+);
Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownContainer.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownDatePicker.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownDatePicker.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownDatePicker.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownDatePicker.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,218 @@
+dojo.provide("dojo.widget.DropdownDatePicker");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.DropdownContainer");
+dojo.require("dojo.widget.DatePicker");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.*");
+dojo.require("dojo.date.format");
+dojo.require("dojo.date.serialize");
+dojo.require("dojo.string.common");
+dojo.require("dojo.i18n.common");
+dojo.requireLocalization("dojo.widget", "DropdownDatePicker");
+
+dojo.widget.defineWidget(
+ "dojo.widget.DropdownDatePicker",
+ dojo.widget.DropdownContainer,
+ {
+ /*
+ summary:
+ A form input for entering dates with a pop-up dojo.widget.DatePicker to aid in selection
+
+ description:
+ This is DatePicker in a DropdownContainer, it supports all features of DatePicker.
+
+ The value displayed in the widget is localized according to the default algorithm provided
+ in dojo.date.format and dojo.date.parse. It is possible to customize the user-visible formatting
+ with either the formatLength or displayFormat attributes. The value sent to the server is
+ typically a locale-independent value in a hidden field as defined by the name attribute.
+ RFC3339 representation is used by default, but other options are available with saveFormat.
+
+ usage:
+ var ddp = dojo.widget.createWidget("DropdownDatePicker", {},
+ dojo.byId("DropdownDatePickerNode"));
+
+ <input dojoType="DropdownDatePicker">
+ */
+
+ iconURL: dojo.uri.dojoUri("src/widget/templates/images/dateIcon.gif"),
+ zIndex: "10",
+
+ //String
+ // Type of visible formatting used, appropriate to locale (choice of long, short, medium or full)
+ // See dojo.date.format for details.
+ formatLength: "short",
+ //String
+ // Pattern used to display formatted date. Setting this overrides the locale-specific settings
+ // which are used by default. See dojo.date.format for a reference which defines the formatting patterns.
+ displayFormat: "",
+ dateFormat: "", // deprecated in 0.5
+ //String
+ // Formatting scheme used when submitting the form element. This formatting is used in a hidden
+ // field (name) intended for server use, and is therefore typically locale-independent.
+ // By default, uses rfc3339 style date formatting (rfc)
+ // Use a pattern string like displayFormat or one of the following:
+ // rfc|iso|posix|unix
+ saveFormat: "",
+ //String|Date
+ // form value property if =='today' will default to todays date
+ value: "",
+ //String
+ // name of the form element, used to create a hidden field by this name for form element submission.
+ name: "",
+
+ // Implement various attributes from DatePicker
+
+ //Integer
+ // total weeks to display default
+ displayWeeks: 6,
+ //Boolean
+ // if true, weekly size of calendar changes to accomodate the month if false, 42 day format is used
+ adjustWeeks: false,
+ //String|Date
+ // first available date in the calendar set
+ startDate: "1492-10-12",
+ //String|Date
+ // last available date in the calendar set
+ endDate: "2941-10-12",
+ //Integer
+ // adjusts the first day of the week 0==Sunday..6==Saturday
+ weekStartsOn: "",
+ //Boolean
+ // disable all incremental controls, must pick a date in the current display
+ staticDisplay: false,
+
+ postMixInProperties: function(localProperties, frag){
+ // summary: see dojo.widget.DomWidget
+
+ dojo.widget.DropdownDatePicker.superclass.postMixInProperties.apply(this, arguments);
+ var messages = dojo.i18n.getLocalization("dojo.widget", "DropdownDatePicker", this.lang);
+ this.iconAlt = messages.selectDate;
+
+ if(typeof(this.value)=='string'&&this.value.toLowerCase()=='today'){
+ this.value = new Date();
+ }
+ if(this.value && isNaN(this.value)){
+ var orig = this.value;
+ this.value = dojo.date.fromRfc3339(this.value);
+ if(!this.value){this.value = new Date(orig); dojo.deprecated("dojo.widget.DropdownDatePicker", "date attributes must be passed in Rfc3339 format", "0.5");}
+ }
+ if(this.value && !isNaN(this.value)){
+ this.value = new Date(this.value);
+ }
+ },
+
+ fillInTemplate: function(args, frag){
+ // summary: see dojo.widget.DomWidget
+ dojo.widget.DropdownDatePicker.superclass.fillInTemplate.call(this, args, frag);
+ //attributes to be passed on to DatePicker
+ var dpArgs = {widgetContainerId: this.widgetId, lang: this.lang, value: this.value,
+ startDate: this.startDate, endDate: this.endDate, displayWeeks: this.displayWeeks,
+ weekStartsOn: this.weekStartsOn, adjustWeeks: this.adjustWeeks, staticDisplay: this.staticDisplay};
+
+ //build the args for DatePicker based on the public attributes of DropdownDatePicker
+ this.datePicker = dojo.widget.createWidget("DatePicker", dpArgs, this.containerNode, "child");
+ dojo.event.connect(this.datePicker, "onValueChanged", this, "onSetDate");
+
+ if(this.value){
+ this.onSetDate();
+ }
+ this.containerNode.style.zIndex = this.zIndex;
+ this.containerNode.explodeClassName = "calendarBodyContainer";
+ this.valueNode.name=this.name;
+ },
+
+ getValue: function(){
+ // summary: return current date in RFC 3339 format
+ return this.valueNode.value; /*String*/
+ },
+
+ getDate: function(){
+ // summary: return current date as a Date object
+ return this.datePicker.value; /*Date*/
+ },
+
+ setValue: function(/*Date|String*/rfcDate){
+ //summary: set the current date from RFC 3339 formatted string or a date object, synonymous with setDate
+ this.setDate(rfcDate);
+ },
+
+ setDate: function(/*Date|String*/dateObj){
+ //summary: set the current date and update the UI
+ this.datePicker.setDate(dateObj);
+ this._synchValueNode();
+ },
+
+ onSetDate: function(){
+ if(this.dateFormat){
+ dojo.deprecated("dojo.widget.DropdownDatePicker",
+ "Must use displayFormat attribute instead of dateFormat. See dojo.date.format for specification.", "0.5");
+ this.inputNode.value = dojo.date.strftime(this.datePicker.value, this.dateFormat, this.lang);
+ }else{
+ this.inputNode.value = dojo.date.format(this.datePicker.value,
+ {formatLength:this.formatLength, datePattern:this.displayFormat, selector:'dateOnly', locale:this.lang});
+ }
+ if(this.value < this.datePicker.startDate||this.value>this.datePicker.endDate){
+ this.inputNode.value = "";
+ }
+ this._synchValueNode();
+ this.onValueChanged(this.getDate());
+ this.hideContainer();
+ },
+
+ onValueChanged: function(/*Date*/dateObj){
+ //summary: triggered when this.value is changed
+ },
+
+ onInputChange: function(){
+ if(this.dateFormat){
+ dojo.deprecated("dojo.widget.DropdownDatePicker",
+ "Cannot parse user input. Must use displayFormat attribute instead of dateFormat. See dojo.date.format for specification.", "0.5");
+ }else{
+ var input = dojo.string.trim(this.inputNode.value);
+ if(input){
+ var inputDate = dojo.date.parse(input,
+ {formatLength:this.formatLength, datePattern:this.displayFormat, selector:'dateOnly', locale:this.lang});
+ if(inputDate){
+ this.setDate(inputDate);
+ }
+ } else {
+ this.valueNode.value = input;
+ }
+ }
+ // If the date entered didn't parse, reset to the old date. KISS, for now.
+ //TODO: usability? should we provide more feedback somehow? an error notice?
+ // seems redundant to do this if the parse failed, but at least until we have validation,
+ // this will fix up the display of entries like 01/32/2006
+ if(input){ this.onSetDate(); }
+ },
+
+ _synchValueNode: function(){
+ var date = this.datePicker.value;
+ var value;
+ switch(this.saveFormat.toLowerCase()){
+ case "rfc": case "iso": case "":
+ value = dojo.date.toRfc3339(date, 'dateOnly');
+ break;
+ case "posix": case "unix":
+ value = Number(date);
+ break;
+ default:
+ value = dojo.date.format(date, {datePattern:this.saveFormat, selector:'dateOnly', locale:this.lang});
+ }
+ this.valueNode.value = value;
+ },
+
+ enable: function() {
+ this.inputNode.disabled = false;
+ this.datePicker.enable();
+ dojo.widget.DropdownDatePicker.superclass.enable.apply(this, arguments);
+ },
+
+ disable: function() {
+ this.inputNode.disabled = true;
+ this.datePicker.disable();
+ dojo.widget.DropdownDatePicker.superclass.disable.apply(this, arguments);
+ }
+ }
+);
Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownDatePicker.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownTimePicker.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownTimePicker.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownTimePicker.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownTimePicker.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,106 @@
+dojo.provide("dojo.widget.DropdownTimePicker");
+
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.DropdownContainer");
+dojo.require("dojo.widget.TimePicker");
+dojo.require("dojo.event.*");
+dojo.require("dojo.html.*");
+dojo.require("dojo.date.format");
+dojo.require("dojo.date.serialize");
+dojo.require("dojo.i18n.common");
+dojo.requireLocalization("dojo.widget", "DropdownTimePicker");
+
+// summary
+// input box with a drop-down gui control, for setting the time (hours, minutes, seconds, am/pm) of an event
+dojo.widget.defineWidget(
+ "dojo.widget.DropdownTimePicker",
+ dojo.widget.DropdownContainer,
+ {
+ // URL
+ // path of icon for button to display time picker widget
+ iconURL: dojo.uri.dojoUri("src/widget/templates/images/timeIcon.gif"),
+
+ // Number
+ // z-index of time picker widget
+ zIndex: "10",
+
+ // pattern used in display of formatted time. Uses locale-specific format by default. See dojo.date.format.
+ displayFormat: "",
+
+ // String
+ // Deprecated. format string for how time is displayed in the input box using strftime, see dojo.date.strftime
+ timeFormat: "",
+
+//FIXME: need saveFormat attribute support
+
+ // type of format appropriate to locale. see dojo.date.format
+ formatLength: "short",
+
+ // String
+ // time value in RFC3339 format (http://www.ietf.org/rfc/rfc3339.txt)
+ // ex: 12:00
+ value: "",
+
+ postMixInProperties: function() {
+ dojo.widget.DropdownTimePicker.superclass.postMixInProperties.apply(this, arguments);
+ var messages = dojo.i18n.getLocalization("dojo.widget", "DropdownTimePicker", this.lang);
+ this.iconAlt = messages.selectTime;
+ },
+
+ fillInTemplate: function(){
+ dojo.widget.DropdownTimePicker.superclass.fillInTemplate.apply(this, arguments);
+
+ var timeProps = { widgetContainerId: this.widgetId, lang: this.lang };
+ this.timePicker = dojo.widget.createWidget("TimePicker", timeProps, this.containerNode, "child");
+ dojo.event.connect(this.timePicker, "onSetTime", this, "onSetTime");
+ dojo.event.connect(this.inputNode, "onchange", this, "onInputChange");
+ this.containerNode.style.zIndex = this.zIndex;
+ this.containerNode.explodeClassName = "timeBorder";
+ if(this.value){
+ this.timePicker.selectedTime.anyTime = false;
+ this.timePicker.setDateTime("2005-01-01T" + this.value);
+ this.timePicker.initData();
+ this.timePicker.initUI();
+ this.onSetTime();
+ }
+ },
+
+ onSetTime: function(){
+ // summary: callback when user sets the time via the TimePicker widget
+ if(this.timePicker.selectedTime.anyTime){
+ this.inputNode.value = "";
+ }else if(this.timeFormat){
+ dojo.deprecated("dojo.widget.DropdownTimePicker",
+ "Must use displayFormat attribute instead of timeFormat. See dojo.date.format for specification.", "0.5");
+ this.inputNode.value = dojo.date.strftime(this.timePicker.time, this.timeFormat, this.lang);
+ }else{
+ this.inputNode.value = dojo.date.format(this.timePicker.time,
+ {formatLength:this.formatLength, datePattern:this.displayFormat, selector:'timeOnly', locale:this.lang});
+ }
+
+ this.hideContainer();
+ },
+
+ onInputChange: function(){
+ // summary: callback when the user has typed in a time value manually
+ this.timePicker.time = "2005-01-01T" + this.inputNode.value; //FIXME: i18n
+ this.timePicker.setDateTime(this.timePicker.time);
+ this.timePicker.initData();
+ this.timePicker.initUI();
+ },
+
+ enable: function() {
+ // summary: enable this widget to accept user input
+ this.inputNode.disabled = false;
+ this.timePicker.enable();
+ dojo.widget.DropdownTimePicker.superclass.enable.apply(this, arguments);
+ },
+
+ disable: function() {
+ // summary: lock this widget so that the user can't change the value
+ this.inputNode.disabled = true;
+ this.timePicker.disable();
+ dojo.widget.DropdownTimePicker.superclass.disable.apply(this, arguments);
+ }
+ }
+);
Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/DropdownTimePicker.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,524 @@
+/* TODO:
+ * - font selector
+ * - test, bug fix, more features :)
+*/
+dojo.provide("dojo.widget.Editor");
+dojo.deprecated("dojo.widget.Editor", "is replaced by dojo.widget.Editor2", "0.5");
+
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Toolbar");
+dojo.require("dojo.widget.RichText");
+dojo.require("dojo.widget.ColorPalette");
+dojo.require("dojo.string.extras");
+
+dojo.widget.tags.addParseTreeHandler("dojo:Editor");
+
+dojo.widget.Editor = function() {
+ dojo.widget.HtmlWidget.call(this);
+ this.contentFilters = [];
+ this._toolbars = [];
+}
+dojo.inherits(dojo.widget.Editor, dojo.widget.HtmlWidget);
+
+dojo.widget.Editor.itemGroups = {
+ textGroup: ["bold", "italic", "underline", "strikethrough"],
+ blockGroup: ["formatBlock", "fontName", "fontSize"],
+ justifyGroup: ["justifyleft", "justifycenter", "justifyright"],
+ commandGroup: ["save", "cancel"],
+ colorGroup: ["forecolor", "hilitecolor"],
+ listGroup: ["insertorderedlist", "insertunorderedlist"],
+ indentGroup: ["outdent", "indent"],
+ linkGroup: ["createlink", "insertimage", "inserthorizontalrule"]
+};
+
+dojo.widget.Editor.formatBlockValues = {
+ "Normal": "p",
+ "Main heading": "h2",
+ "Sub heading": "h3",
+ "Sub sub heading": "h4",
+ "Preformatted": "pre"
+};
+
+dojo.widget.Editor.fontNameValues = {
+ "Arial": "Arial, Helvetica, sans-serif",
+ "Verdana": "Verdana, sans-serif",
+ "Times New Roman": "Times New Roman, serif",
+ "Courier": "Courier New, monospace"
+};
+
+dojo.widget.Editor.fontSizeValues = {
+ "1 (8 pt)" : "1",
+ "2 (10 pt)": "2",
+ "3 (12 pt)": "3",
+ "4 (14 pt)": "4",
+ "5 (18 pt)": "5",
+ "6 (24 pt)": "6",
+ "7 (36 pt)": "7"
+};
+
+dojo.widget.Editor.defaultItems = [
+ "commandGroup", "|", "blockGroup", "|", "textGroup", "|", "colorGroup", "|", "justifyGroup", "|", "listGroup", "indentGroup", "|", "linkGroup"
+];
+
+// ones we support by default without asking the RichText component
+// NOTE: you shouldn't put buttons like bold, italic, etc in here
+dojo.widget.Editor.supportedCommands = ["save", "cancel", "|", "-", "/", " "];
+
+dojo.lang.extend(dojo.widget.Editor, {
+ widgetType: "Editor",
+
+ saveUrl: "",
+ saveMethod: "post",
+ saveArgName: "editorContent",
+ closeOnSave: false,
+ items: dojo.widget.Editor.defaultItems,
+ formatBlockItems: dojo.lang.shallowCopy(dojo.widget.Editor.formatBlockValues),
+ fontNameItems: dojo.lang.shallowCopy(dojo.widget.Editor.fontNameValues),
+ fontSizeItems: dojo.lang.shallowCopy(dojo.widget.Editor.fontSizeValues),
+
+ // used to get the properties of an item if it is given as a string
+ getItemProperties: function(name) {
+ var props = {};
+ switch(name.toLowerCase()) {
+ case "bold":
+ case "italic":
+ case "underline":
+ case "strikethrough":
+ props.toggleItem = true;
+ break;
+
+ case "justifygroup":
+ props.defaultButton = "justifyleft";
+ props.preventDeselect = true;
+ props.buttonGroup = true;
+ break;
+
+ case "listgroup":
+ props.buttonGroup = true;
+ break;
+
+ case "save":
+ case "cancel":
+ props.label = dojo.string.capitalize(name);
+ break;
+
+ case "forecolor":
+ case "hilitecolor":
+ props.name = name;
+ props.toggleItem = true; // FIXME: they aren't exactly toggle items
+ props.icon = this.getCommandImage(name);
+ break;
+
+ case "formatblock":
+ props.name = "formatBlock";
+ props.values = this.formatBlockItems;
+ break;
+
+ case "fontname":
+ props.name = "fontName";
+ props.values = this.fontNameItems;
+
+ case "fontsize":
+ props.name = "fontSize";
+ props.values = this.fontSizeItems;
+ }
+ return props;
+ },
+
+ validateItems: true, // set to false to add items, regardless of support
+ focusOnLoad: true,
+ minHeight: "1em",
+
+ _richText: null, // RichText widget
+ _richTextType: "RichText",
+
+ _toolbarContainer: null, // ToolbarContainer widget
+ _toolbarContainerType: "ToolbarContainer",
+
+ _toolbars: [],
+ _toolbarType: "Toolbar",
+
+ _toolbarItemType: "ToolbarItem",
+
+ buildRendering: function(args, frag) {
+ // get the node from args/frag
+ var node = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
+ var trt = dojo.widget.createWidget(this._richTextType, {
+ focusOnLoad: this.focusOnLoad,
+ minHeight: this.minHeight
+ }, node)
+ var _this = this;
+ // this appears to fix a weird timing bug on Safari
+ setTimeout(function(){
+ _this.setRichText(trt);
+
+ _this.initToolbar();
+
+ _this.fillInTemplate(args, frag);
+ }, 0);
+ },
+
+ setRichText: function(richText) {
+ if(this._richText && this._richText == richText) {
+ dojo.debug("Already set the richText to this richText!");
+ return;
+ }
+
+ if(this._richText && !this._richText.isClosed) {
+ dojo.debug("You are switching richTexts yet you haven't closed the current one. Losing reference!");
+ }
+ this._richText = richText;
+ dojo.event.connect(this._richText, "close", this, "onClose");
+ dojo.event.connect(this._richText, "onLoad", this, "onLoad");
+ dojo.event.connect(this._richText, "onDisplayChanged", this, "updateToolbar");
+ if(this._toolbarContainer) {
+ this._toolbarContainer.enable();
+ this.updateToolbar(true);
+ }
+ },
+
+ initToolbar: function() {
+ // var tic = new Date();
+ if(this._toolbarContainer) { return; } // only create it once
+ this._toolbarContainer = dojo.widget.createWidget(this._toolbarContainerType);
+ var tb = this.addToolbar();
+ var last = true;
+ for(var i = 0; i < this.items.length; i++) {
+ if(this.items[i] == "\n") { // new row
+ tb = this.addToolbar();
+ } else {
+ if((this.items[i] == "|")&&(!last)){
+ last = true;
+ }else{
+ last = this.addItem(this.items[i], tb);
+ }
+ }
+ }
+ this.insertToolbar(this._toolbarContainer.domNode, this._richText.domNode);
+ // alert(new Date - tic);
+ },
+
+ // allow people to override this so they can make their own placement logic
+ insertToolbar: function(tbNode, richTextNode) {
+ dojo.html.insertBefore(tbNode, richTextNode);
+ //dojo.html.insertBefore(this._toolbarContainer.domNode, this._richText.domNode);
+ },
+
+ addToolbar: function(toolbar) {
+ this.initToolbar();
+ if(!(toolbar instanceof dojo.widget.Toolbar)) {
+ toolbar = dojo.widget.createWidget(this._toolbarType);
+ }
+ this._toolbarContainer.addChild(toolbar);
+ this._toolbars.push(toolbar);
+ return toolbar;
+ },
+
+ addItem: function(item, tb, dontValidate) {
+ if(!tb) { tb = this._toolbars[0]; }
+ var cmd = ((item)&&(!dojo.lang.isUndefined(item["getValue"]))) ? cmd = item["getValue"](): item;
+
+ var groups = dojo.widget.Editor.itemGroups;
+ if(item instanceof dojo.widget.ToolbarItem) {
+ tb.addChild(item);
+ } else if(groups[cmd]) {
+ var group = groups[cmd];
+ var worked = true;
+ if(cmd == "justifyGroup" || cmd == "listGroup") {
+ var btnGroup = [cmd];
+ for(var i = 0 ; i < group.length; i++) {
+ if(dontValidate || this.isSupportedCommand(group[i])) {
+ btnGroup.push(this.getCommandImage(group[i]));
+ }else{
+ worked = false;
+ }
+ }
+ if(btnGroup.length){
+ /*
+ // the addChild interface is assinine. Work around it.
+ var tprops = this.getItemProperties(cmd);
+ var tmpGroup = dojo.widget.createWidget("ToolbarButtonGroup", tprops);
+ dojo.debug(btnGroup);
+ dojo.event.connect(tmpGroup, "onClick", this, "_action");
+ dojo.event.connect(tmpGroup, "onChangeSelect", this, "_action");
+ */
+ var btn = tb.addChild(btnGroup, null, this.getItemProperties(cmd));
+ dojo.event.connect(btn, "onClick", this, "_action");
+ dojo.event.connect(btn, "onChangeSelect", this, "_action");
+ }
+ return worked;
+ } else {
+ for(var i = 0; i < group.length; i++) {
+ if(!this.addItem(group[i], tb)){
+ worked = false;
+ }
+ }
+ return worked;
+ }
+ } else {
+ if((!dontValidate)&&(!this.isSupportedCommand(cmd))){
+ return false;
+ }
+ if(dontValidate || this.isSupportedCommand(cmd)) {
+ cmd = cmd.toLowerCase();
+ if(cmd == "formatblock") {
+ var select = dojo.widget.createWidget("ToolbarSelect", {
+ name: "formatBlock",
+ values: this.formatBlockItems
+ });
+ tb.addChild(select);
+ var _this = this;
+ dojo.event.connect(select, "onSetValue", function(item, value) {
+ _this.onAction("formatBlock", value);
+ });
+ } else if(cmd == "fontname") {
+ var select = dojo.widget.createWidget("ToolbarSelect", {
+ name: "fontName",
+ values: this.fontNameItems
+ });
+ tb.addChild(select);
+ dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
+ this.onAction("fontName", value);
+ }));
+ } else if(cmd == "fontsize") {
+ var select = dojo.widget.createWidget("ToolbarSelect", {
+ name: "fontSize",
+ values: this.fontSizeItems
+ });
+ tb.addChild(select);
+ dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
+ this.onAction("fontSize", value);
+ }));
+ } else if(dojo.lang.inArray(cmd, ["forecolor", "hilitecolor"])) {
+ var btn = tb.addChild(dojo.widget.createWidget("ToolbarColorDialog", this.getItemProperties(cmd)));
+ dojo.event.connect(btn, "onSetValue", this, "_setValue");
+ } else {
+ var btn = tb.addChild(this.getCommandImage(cmd), null, this.getItemProperties(cmd));
+ if(cmd == "save"){
+ dojo.event.connect(btn, "onClick", this, "_save");
+ }else if(cmd == "cancel"){
+ dojo.event.connect(btn, "onClick", this, "_close");
+ } else {
+ dojo.event.connect(btn, "onClick", this, "_action");
+ dojo.event.connect(btn, "onChangeSelect", this, "_action");
+ }
+ }
+ }
+ }
+ return true;
+ },
+
+ enableToolbar: function() {
+ if(this._toolbarContainer) {
+ this._toolbarContainer.domNode.style.display = "";
+ this._toolbarContainer.enable();
+ }
+ },
+
+ disableToolbar: function(hide){
+ if(hide){
+ if(this._toolbarContainer){
+ this._toolbarContainer.domNode.style.display = "none";
+ }
+ }else{
+ if(this._toolbarContainer){
+ this._toolbarContainer.disable();
+ }
+ }
+ },
+
+ _updateToolbarLastRan: null,
+ _updateToolbarTimer: null,
+ _updateToolbarFrequency: 500,
+
+ updateToolbar: function(force) {
+ if(!this._toolbarContainer) { return; }
+
+ // keeps the toolbar from updating too frequently
+ // TODO: generalize this functionality?
+ var diff = new Date() - this._updateToolbarLastRan;
+ if(!force && this._updateToolbarLastRan && (diff < this._updateToolbarFrequency)) {
+ clearTimeout(this._updateToolbarTimer);
+ var _this = this;
+ this._updateToolbarTimer = setTimeout(function() {
+ _this.updateToolbar();
+ }, this._updateToolbarFrequency/2);
+ return;
+ } else {
+ this._updateToolbarLastRan = new Date();
+ }
+ // end frequency checker
+
+ var items = this._toolbarContainer.getItems();
+ for(var i = 0; i < items.length; i++) {
+ var item = items[i];
+ if(item instanceof dojo.widget.ToolbarSeparator) { continue; }
+ var cmd = item._name;
+ if (cmd == "save" || cmd == "cancel") { continue; }
+ else if(cmd == "justifyGroup") {
+ try {
+ if(!this._richText.queryCommandEnabled("justifyleft")) {
+ item.disable(false, true);
+ } else {
+ item.enable(false, true);
+ var jitems = item.getItems();
+ for(var j = 0; j < jitems.length; j++) {
+ var name = jitems[j]._name;
+ var value = this._richText.queryCommandValue(name);
+ if(typeof value == "boolean" && value) {
+ value = name;
+ break;
+ } else if(typeof value == "string") {
+ value = "justify"+value;
+ } else {
+ value = null;
+ }
+ }
+ if(!value) { value = "justifyleft"; } // TODO: query actual style
+ item.setValue(value, false, true);
+ }
+ } catch(err) {}
+ } else if(cmd == "listGroup") {
+ var litems = item.getItems();
+ for(var j = 0; j < litems.length; j++) {
+ this.updateItem(litems[j]);
+ }
+ } else {
+ this.updateItem(item);
+ }
+ }
+ },
+
+ updateItem: function(item) {
+ try {
+ var cmd = item._name;
+ var enabled = this._richText.queryCommandEnabled(cmd);
+ item.setEnabled(enabled, false, true);
+
+ var active = this._richText.queryCommandState(cmd);
+ if(active && cmd == "underline") {
+ // don't activate underlining if we are on a link
+ active = !this._richText.queryCommandEnabled("unlink");
+ }
+ item.setSelected(active, false, true);
+ return true;
+ } catch(err) {
+ return false;
+ }
+ },
+
+ supportedCommands: dojo.widget.Editor.supportedCommands.concat(),
+
+ isSupportedCommand: function(cmd) {
+ // FIXME: how do we check for ActiveX?
+ var yes = dojo.lang.inArray(cmd, this.supportedCommands);
+ if(!yes) {
+ try {
+ var richText = this._richText || dojo.widget.HtmlRichText.prototype;
+ yes = richText.queryCommandAvailable(cmd);
+ } catch(E) {}
+ }
+ return yes;
+ },
+
+ getCommandImage: function(cmd) {
+ if(cmd == "|") {
+ return cmd;
+ } else {
+ return dojo.uri.dojoUri("src/widget/templates/buttons/" + cmd + ".gif");
+ }
+ },
+
+ _action: function(e) {
+ this._fire("onAction", e.getValue());
+ },
+
+ _setValue: function(a, b) {
+ this._fire("onAction", a.getValue(), b);
+ },
+
+ _save: function(e){
+ // FIXME: how should this behave when there's a larger form in play?
+ if(!this._richText.isClosed){
+ if(this.saveUrl.length){
+ var content = {};
+ content[this.saveArgName] = this.getHtml();
+ dojo.io.bind({
+ method: this.saveMethod,
+ url: this.saveUrl,
+ content: content
+ });
+ }else{
+ dojo.debug("please set a saveUrl for the editor");
+ }
+ if(this.closeOnSave){
+ this._richText.close(e.getName().toLowerCase() == "save");
+ }
+ }
+ },
+
+ _close: function(e) {
+ if(!this._richText.isClosed) {
+ this._richText.close(e.getName().toLowerCase() == "save");
+ }
+ },
+
+ onAction: function(cmd, value) {
+ switch(cmd) {
+ case "createlink":
+ if(!(value = prompt("Please enter the URL of the link:", "http://"))) {
+ return;
+ }
+ break;
+ case "insertimage":
+ if(!(value = prompt("Please enter the URL of the image:", "http://"))) {
+ return;
+ }
+ break;
+ }
+ this._richText.execCommand(cmd, value);
+ },
+
+ fillInTemplate: function(args, frag) {
+ // dojo.event.connect(this, "onResized", this._richText, "onResized");
+ },
+
+ _fire: function(eventName) {
+ if(dojo.lang.isFunction(this[eventName])) {
+ var args = [];
+ if(arguments.length == 1) {
+ args.push(this);
+ } else {
+ for(var i = 1; i < arguments.length; i++) {
+ args.push(arguments[i]);
+ }
+ }
+ this[eventName].apply(this, args);
+ }
+ },
+
+ getHtml: function(){
+ this._richText.contentFilters = this._richText.contentFilters.concat(this.contentFilters);
+ return this._richText.getEditorContent();
+ },
+
+ getEditorContent: function(){
+ return this.getHtml();
+ },
+
+ onClose: function(save, hide){
+ this.disableToolbar(hide);
+ if(save) {
+ this._fire("onSave");
+ } else {
+ this._fire("onCancel");
+ }
+ },
+
+ // events baby!
+ onLoad: function(){},
+ onSave: function(){},
+ onCancel: function(){}
+});
+
Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor.js
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor2.js
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor2.js?view=auto&rev=473755
==============================================================================
--- jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor2.js (added)
+++ jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor2.js Sat Nov 11 08:44:22 2006
@@ -0,0 +1,656 @@
+/* TODO:
+ * - font selector
+ * - test, bug fix, more features :)
+*/
+dojo.provide("dojo.widget.Editor2");
+
+dojo.require("dojo.io.*");
+dojo.require("dojo.html.*");
+dojo.require("dojo.html.layout");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.RichText");
+dojo.require("dojo.widget.Editor2Toolbar");
+
+// Object: Manager of current focused Editor2 Instance and available editor2 commands
+dojo.widget.Editor2Manager = {
+ _currentInstance: null,
+ _loadedCommands: {},
+
+ // Object: state a command may be in
+ commandState: {Disabled: 0, Latched: 1, Enabled: 2},
+
+ getCurrentInstance: function(){
+ // summary: Return the current focused Editor2 instance
+ return this._currentInstance;
+ },
+ setCurrentInstance: function(/*Widget*/inst){
+ // summary: Set current focused Editor2 instance
+ this._currentInstance = inst;
+ },
+ registerCommand: function(/*String*/name, /*Object*/cmd){
+ // summary: Register an Editor2 command
+ // name: name of the command (case insensitive)
+ // cmd: an object which implements interface dojo.widget.Editor2Command
+ name = name.toLowerCase();
+ if(this._loadedCommands[name]){
+ delete this._loadedCommands[name];
+ }
+ this._loadedCommands[name] = cmd;
+ },
+ getCommand: function(/*String*/name){
+ // summary: Return Editor2 command with the given name
+ // name: name of the command (case insensitive)
+ name = name.toLowerCase();
+ var oCommand = this._loadedCommands[name];
+ if(oCommand){
+ return oCommand;
+ }
+
+ switch(name){
+ case 'htmltoggle':
+ //Editor2 natively provide the htmltoggle functionalitity
+ //and it is treated as a builtin command
+ oCommand = new dojo.widget.Editor2BrowserCommand(name);
+ break;
+ case 'formatblock':
+ oCommand = new dojo.widget.Editor2FormatBlockCommand(name);
+ break;
+ case 'anchor':
+ oCommand = new dojo.widget.Editor2Command(name);
+ break;
+
+ //dialog command
+ case 'createlink':
+ oCommand = new dojo.widget.Editor2DialogCommand(name,
+ {contentFile: "dojo.widget.Editor2Plugin.CreateLinkDialog",
+ contentClass: "Editor2CreateLinkDialog",
+ title: "Insert/Edit Link", width: "300px", height: "200px"});
+ break;
+ case 'insertimage':
+ oCommand = new dojo.widget.Editor2DialogCommand(name,
+ {contentFile: "dojo.widget.Editor2Plugin.InsertImageDialog",
+ contentClass: "Editor2InsertImageDialog",
+ title: "Insert/Edit Image", width: "400px", height: "270px"});
+ break;
+ // By default we assume that it is a builtin simple command.
+ default:
+ var curtInst = this.getCurrentInstance();
+ if((curtInst && curtInst.queryCommandAvailable(name)) ||
+ (!curtInst && dojo.widget.Editor2.prototype.queryCommandAvailable(name))){
+ oCommand = new dojo.widget.Editor2BrowserCommand(name);
+ }else{
+ dojo.debug("dojo.widget.Editor2Manager.getCommand: Unknown command "+name);
+ return;
+ }
+ }
+ this._loadedCommands[name] = oCommand;
+ return oCommand;
+ },
+ destroy: function(){
+ // summary: Cleaning up. This is called automatically on page unload.
+ this._currentInstance = null;
+ for(var cmd in this._loadedCommands){
+ this._loadedCommands[cmd].destory();
+ }
+ }
+};
+
+dojo.addOnUnload(dojo.widget.Editor2Manager, "destroy");
+
+// summary:
+// dojo.widget.Editor2Command is the base class for all command in Editor2
+dojo.lang.declare("dojo.widget.Editor2Command",null,{
+ initializer: function(name){
+ // summary: Constructor of this class
+ this._name = name;
+ },
+ //this function should be re-implemented in subclass
+ execute: function(para){
+ // summary: Execute the command. should be implemented in subclass
+ dojo.unimplemented("dojo.widget.Editor2Command.execute");
+ },
+ //default implemetation always returns Enabled
+ getState: function(){
+ // summary:
+ // Return the state of the command. The default behavior is
+ // to always return Enabled
+ return dojo.widget.Editor2Manager.commandState.Enabled;
+ },
+ destory: function(){
+ // summary: Destructor
+ }
+ }
+);
+
+// summary:
+// dojo.widget.Editor2BrowserCommand is the base class for all the browser built
+// in commands
+dojo.lang.declare("dojo.widget.Editor2BrowserCommand", dojo.widget.Editor2Command, {
+ execute: function(para){
+ var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
+ if(curInst){
+ curInst.execCommand(this._name, para);
+ }
+ },
+ getState: function(){
+ var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
+ if(curInst){
+ try{
+ if(curInst.queryCommandEnabled(this._name)){
+ if(curInst.queryCommandState(this._name)){
+ return dojo.widget.Editor2Manager.commandState.Latched;
+ }else{
+ return dojo.widget.Editor2Manager.commandState.Enabled;
+ }
+ }else{
+ return dojo.widget.Editor2Manager.commandState.Disabled;
+ }
+ }catch (e) {
+ //dojo.debug("exception when getting state for command "+this._name+": "+e);
+ return dojo.widget.Editor2Manager.commandState.Enabled;
+ }
+ }
+ return dojo.widget.Editor2Manager.commandState.Disabled;
+ },
+ getValue: function(){
+ var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
+ if(curInst){
+ try{
+ return curInst.queryCommandValue(this._name);
+ }catch(e){}
+ }
+ }
+ }
+);
+
+dojo.lang.declare("dojo.widget.Editor2FormatBlockCommand", dojo.widget.Editor2BrowserCommand, {
+ /* In none-ActiveX mode under IE, <p> and no <p> text can not be distinguished
+ getCurrentValue: function(){
+ var curInst = dojo.widget.Editor2Manager.getCurrentInstance();
+ if(!curInst){ return ''; }
+
+ var h = dojo.render.html;
+
+ // safari f's us for selection primitives
+ if(h.safari){ return ''; }
+
+ var selectedNode = (h.ie) ? curInst.document.selection.createRange().parentElement() : curInst.window.getSelection().anchorNode;
+ // make sure we actuall have an element
+ while((selectedNode)&&(selectedNode.nodeType != 1)){
+ selectedNode = selectedNode.parentNode;
+ }
+ if(!selectedNode){ return ''; }
+
+ var formats = ["p", "pre", "h1", "h2", "h3", "h4", "h5", "h6", "address"];
+ // gotta run some specialized updates for the various
+ // formatting options
+ var type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())];
+ while((selectedNode!=curInst.editNode)&&(!type)){
+ selectedNode = selectedNode.parentNode;
+ if(!selectedNode){ break; }
+ type = formats[dojo.lang.find(formats, selectedNode.nodeName.toLowerCase())];
+ }
+ if(!type){
+ type = "";
+ }
+ return type;
+ }*/
+ }
+);
+
+dojo.require("dojo.widget.FloatingPane");
+// summary:
+// dojo.widget.Editor2Dialog provides a Dialog which can be modal or normal for the Editor2.
+dojo.widget.defineWidget(
+ "dojo.widget.Editor2Dialog",
+ [dojo.widget.HtmlWidget, dojo.widget.FloatingPaneBase, dojo.widget.ModalDialogBase],
+ {
+ templatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorDialog.html"),
+ // Boolean: Whether this is a modal dialog. True by default.
+ modal: true,
+// refreshOnShow: true, //for debug for now
+
+ // String: Wwidth of the dialog. None by default
+ width: false,
+ // String: Height of the dialog. None by default
+ height: false,
+
+ // String: startup state of the dialog
+ windowState: "minimized",
+
+ displayCloseAction: true,
+
+ contentFile: "",
+ contentClass: "",
+
+ fillInTemplate: function(args, frag){
+ this.fillInFloatingPaneTemplate(args, frag);
+ dojo.widget.Editor2Dialog.superclass.fillInTemplate.call(this, args, frag);
+ },
+ postCreate: function(){
+ if(this.contentFile){
+ dojo.require(this.contentFile);
+ }
+ if(this.modal){
+ dojo.widget.ModalDialogBase.prototype.postCreate.call(this);
+ }else{
+ with(this.domNode.style) {
+ zIndex = 999;
+ display = "none";
+ }
+ }
+ dojo.widget.FloatingPaneBase.prototype.postCreate.apply(this, arguments);
+ dojo.widget.Editor2Dialog.superclass.postCreate.call(this);
+ if(this.width && this.height){
+ with(this.domNode.style){
+ width = this.width;
+ height = this.height;
+ }
+ }
+ },
+ createContent: function(){
+ if(!this.contentWidget && this.contentClass){
+ this.contentWidget = dojo.widget.createWidget(this.contentClass);
+ this.addChild(this.contentWidget);
+ }
+ },
+ show: function(){
+ if(!this.contentWidget){
+ //buggy IE: if the dialog is hidden, the button widgets
+ //in the dialog can not be shown, so show it temporary (as the
+ //dialog may decide not to show it in loadContent() later)
+ dojo.widget.Editor2Dialog.superclass.show.apply(this, arguments);
+ this.createContent();
+ dojo.widget.Editor2Dialog.superclass.hide.call(this);
+ }
+
+ if(!this.contentWidget || !this.contentWidget.loadContent()){
+ return;
+ }
+ this.showFloatingPane();
+ dojo.widget.Editor2Dialog.superclass.show.apply(this, arguments);
+ if(this.modal){
+ this.showModalDialog();
+ }
+ this.placeModalDialog();
+ if(this.modal){
+ //place the background div under this modal pane
+ this.shared.bg.style.zIndex = this.domNode.style.zIndex-1;
+ }
+ },
+ onShow: function(){
+ dojo.widget.Editor2Dialog.superclass.onShow.call(this);
+ this.onFloatingPaneShow();
+ },
+ closeWindow: function(){
+ this.hide();
+ dojo.widget.Editor2Dialog.superclass.closeWindow.apply(this, arguments);
+ },
+ hide: function(){
+ if(this.modal){
+ this.hideModalDialog();
+ }
+ dojo.widget.Editor2Dialog.superclass.hide.call(this);
+ }
+ }
+);
+
+// summary:
+// dojo.widget.Editor2DialogContent is the actual content of a Editor2Dialog.
+// This class should be subclassed to provide the content.
+dojo.widget.defineWidget(
+ "dojo.widget.Editor2DialogContent",
+ dojo.widget.HtmlWidget,
+{
+ widgetsInTemplate: true,
+
+ loadContent:function(){
+ // summary: Load the content. Called by Editor2Dialog when first shown
+ return true;
+ },
+ cancel: function(){
+ // summary: Default handler when cancel button is clicked.
+ this.parent.hide();
+ }
+});
+
+// summary:
+// dojo.widget.Editor2DialogCommand provides an easy way to popup a dialog when
+// the command is executed.
+dojo.lang.declare("dojo.widget.Editor2DialogCommand", dojo.widget.Editor2BrowserCommand,
+ function(name, dialogParas){
+ this.dialogParas = dialogParas;
+ },
+{
+ execute: function(){
+ if(!this.dialog){
+ if(!this.dialogParas.contentFile || !this.dialogParas.contentClass){
+ alert("contentFile and contentClass should be set for dojo.widget.Editor2DialogCommand.dialogParas!");
+ return;
+ }
+ this.dialog = dojo.widget.createWidget("Editor2Dialog", this.dialogParas);
+
+ dojo.body().appendChild(this.dialog.domNode);
+
+ dojo.event.connect(this, "destroy", this.dialog, "destroy");
+ }
+ this.dialog.show();
+ }
+});
+
+// summary:
+// dojo.widget.Editor2 is the WYSIWYG editor in dojo with toolbar. It supports a plugin
+// framework which can be used to extend the functionalities of the editor, such as
+// adding a context menu, table operation etc.
+// description:
+// Plugins are available using dojo's require syntax. Please find available built-in plugins
+// under src/widget/Editor2Plugin.
+dojo.widget.defineWidget(
+ "dojo.widget.Editor2",
+ dojo.widget.RichText,
+ {
+// // String: url to which save action should send content to
+// saveUrl: "",
+// // String: HTTP method for save (post or get)
+// saveMethod: "post",
+// saveArgName: "editorContent",
+// closeOnSave: false,
+
+ // Boolean: Whether to share toolbar with other instances of Editor2
+ shareToolbar: false,
+ // Boolean: Whether the toolbar should scroll to keep it in the view
+ toolbarAlwaysVisible: false,
+
+// htmlEditing: false,
+
+ toolbarWidget: null,
+ scrollInterval: null,
+
+ // Object: dojo.uri.Uri object to specify the template file for the toolbar
+ toolbarTemplatePath: dojo.uri.dojoUri("src/widget/templates/EditorToolbarOneline.html"),
+ // Object: dojo.uri.Uri object to specify the css file for the toolbar
+ toolbarTemplateCssPath: null,
+// toolbarTemplatePath: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbarFCKStyle.html"),
+// toolbarTemplateCssPath: dojo.uri.dojoUri("src/widget/templates/Editor2/FCKDefault/EditorToolbarFCKStyle.css"),
+
+ _inSourceMode: false,
+ _htmlEditNode: null,
+
+ editorOnLoad: function(){
+ // summary:
+ // Create toolbar and other initialization routines. This is called after
+ // the finish of the loading of document in the editing element
+// dojo.profile.start("dojo.widget.Editor2::editorOnLoad");
+
+ dojo.event.topic.publish("dojo.widget.Editor2::preLoadingToolbar", this);
+ if(this.toolbarAlwaysVisible){
+ dojo.require("dojo.widget.Editor2Plugin.AlwaysShowToolbar");
+ }
+
+ var toolbars = dojo.widget.byType("Editor2Toolbar");
+ if((!toolbars.length)||(!this.shareToolbar)){
+ if(this.toolbarWidget){
+ this.toolbarWidget.show();
+ //re-add the toolbar to the new domNode (caused by open() on another element)
+ dojo.html.insertBefore(this.toolbarWidget.domNode, this.domNode.firstChild);
+ }else{
+ var tbOpts = {};
+ tbOpts.templatePath = this.toolbarTemplatePath;
+ if(this.toolbarTemplateCssPath){
+ tbOpts.templateCssPath = this.toolbarTemplateCssPath;
+ }
+ this.toolbarWidget = dojo.widget.createWidget("Editor2Toolbar", tbOpts, this.domNode.firstChild, "before");
+
+ dojo.event.connect(this, "close", this.toolbarWidget, "hide");
+
+ this.toolbarLoaded();
+ }
+ }else{
+ // FIXME: selecting in one shared toolbar doesn't clobber
+ // selection in the others. This is problematic.
+ this.toolbarWidget = toolbars[0];
+ }
+
+ dojo.event.topic.registerPublisher("Editor2.clobberFocus", this, "clobberFocus");
+ dojo.event.topic.subscribe("Editor2.clobberFocus", this, "setBlur");
+
+ dojo.event.topic.publish("dojo.widget.Editor2::onLoad", this);
+// dojo.profile.end("dojo.widget.Editor2::editorOnLoad");
+ },
+
+ //event for plugins to use
+ toolbarLoaded: function(){
+ // summary:
+ // Fired when the toolbar for this editor is created.
+ // This event is for plugins to use
+ },
+
+ //TODO: provide a query mechanism about loaded plugins?
+ registerLoadedPlugin: function(/*Object*/obj){
+ // summary: Register a plugin which is loaded for this instance
+ if(!this.loadedPlugins){
+ this.loadedPlugins = [];
+ }
+ this.loadedPlugins.push(obj);
+ },
+ unregisterLoadedPlugin: function(/*Object*/obj){
+ // summery: Delete a loaded plugin for this instance
+ for(var i in this.loadedPlugins){
+ if(this.loadedPlugins[i] === obj){
+ delete this.loadedPlugins[i];
+ return;
+ }
+ }
+ dojo.debug("dojo.widget.Editor2.unregisterLoadedPlugin: unknow plugin object: "+obj);
+ },
+
+ //overload the original ones to provide extra commands
+ execCommand: function(/*String*/command, argument){
+ switch(command.toLowerCase()){
+ case 'htmltoggle':
+ this.toggleHtmlEditing();
+ break;
+ default:
+ dojo.widget.Editor2.superclass.execCommand.apply(this, arguments);
+ }
+ },
+ queryCommandEnabled: function(/*String*/command, argument){
+ switch(command.toLowerCase()){
+ case 'htmltoggle':
+ return true;
+ default:
+ if(this._inSourceMode){ return false;}
+ return dojo.widget.Editor2.superclass.queryCommandEnabled.apply(this, arguments);
+ }
+ },
+ queryCommandState: function(/*String*/command, argument){
+ switch(command.toLowerCase()){
+ case 'htmltoggle':
+ return this._inSourceMode;
+ default:
+ return dojo.widget.Editor2.superclass.queryCommandState.apply(this, arguments);
+ }
+ },
+
+ onClick: function(/*Event*/e){
+ dojo.widget.Editor2.superclass.onClick.call(this, e);
+ //if Popup is used, call dojo.widget.PopupManager.onClick
+ //manually when click in the editing area to close all
+ //open popups (dropdowns)
+ if(dojo.widget.PopupManager){
+ if(!e){ //IE
+ e = this.window.event;
+ }
+ dojo.widget.PopupManager.onClick(e);
+ }
+ },
+
+ clobberFocus: function(){
+ // summary: stub to signal other instances to clobber focus
+ },
+ toggleHtmlEditing: function(){
+ // summary: toggle between WYSIWYG mode and HTML source mode
+ if(this===dojo.widget.Editor2Manager.getCurrentInstance()){
+ if(!this._inSourceMode){
+ this._inSourceMode = true;
+
+ if(!this._htmlEditNode){
+ this._htmlEditNode = dojo.doc().createElement("textarea");
+ dojo.html.insertAfter(this._htmlEditNode, this.editorObject);
+ }
+ this._htmlEditNode.style.display = "";
+ this._htmlEditNode.style.width = "100%";
+ this._htmlEditNode.style.height = dojo.html.getBorderBox(this.editNode).height+"px";
+ this._htmlEditNode.value = this.editNode.innerHTML;
+
+ //activeX object (IE) doesn't like to be hidden, so move it outside of screen instead
+ with(this.editorObject.style){
+ position = "absolute";
+ left = "-2000px";
+ top = "-2000px";
+ }
+ }else{
+ this._inSourceMode = false;
+
+ //In IE activeX mode, if _htmlEditNode is focused,
+ //when toggling, an error would occur, so unfocus it
+ this._htmlEditNode.blur();
+
+ with(this.editorObject.style){
+ position = "";
+ left = "";
+ top = "";
+ }
+
+ dojo.lang.setTimeout(this, "replaceEditorContent", 1, this._htmlEditNode.value);
+ this._htmlEditNode.style.display = "none";
+ this.focus();
+ }
+ this.updateToolbar(true);
+ }
+ },
+
+ setFocus: function(){
+ // summary: focus is set on this instance
+// dojo.debug("setFocus: start "+this.widgetId);
+ if(dojo.widget.Editor2Manager.getCurrentInstance() === this){ return; }
+
+ this.clobberFocus();
+// dojo.debug("setFocus:", this);
+ dojo.widget.Editor2Manager.setCurrentInstance(this);
+ },
+
+ setBlur: function(){
+ // summary: focus on this instance is lost
+// dojo.debug("setBlur:", this);
+ //dojo.event.disconnect(this.toolbarWidget, "exec", this, "execCommand");
+ },
+
+ saveSelection: function(){
+ // summary: save the current selection for restoring it
+ this._bookmark = null;
+ this._bookmark = dojo.withGlobal(this.window, dojo.html.selection.getBookmark);
+ },
+ restoreSelection: function(){
+ // summary: restore the last saved selection
+ if(this._bookmark){
+ this.focus(); //require for none-activeX IE
+ dojo.withGlobal(this.window, "moveToBookmark", dojo.html.selection, [this._bookmark]);
+ this._bookmark = null;
+ }else{
+ dojo.debug("restoreSelection: no saved selection is found!");
+ }
+ },
+
+ _updateToolbarLastRan: null,
+ _updateToolbarTimer: null,
+ _updateToolbarFrequency: 500,
+
+ updateToolbar: function(/*Boolean*/force){
+ // summary: update the associated toolbar of this Editor2
+ if((!this.isLoaded)||(!this.toolbarWidget)){ return; }
+
+ // keeps the toolbar from updating too frequently
+ // TODO: generalize this functionality?
+ var diff = new Date() - this._updateToolbarLastRan;
+ if( (!force)&&(this._updateToolbarLastRan)&&
+ ((diff < this._updateToolbarFrequency)) ){
+
+ clearTimeout(this._updateToolbarTimer);
+ var _this = this;
+ this._updateToolbarTimer = setTimeout(function() {
+ _this.updateToolbar();
+ }, this._updateToolbarFrequency/2);
+ return;
+
+ }else{
+ this._updateToolbarLastRan = new Date();
+ }
+ // end frequency checker
+
+ //IE has the habit of generating events even when this editor is blurred, prevent this
+ if(dojo.widget.Editor2Manager.getCurrentInstance() !== this){ return; }
+
+ this.toolbarWidget.update();
+ },
+
+ destroy: function(/*Boolean*/finalize){
+ this._htmlEditNode = null;
+ dojo.event.disconnect(this, "close", this.toolbarWidget, "hide");
+ if(!finalize){
+ this.toolbarWidget.destroy();
+ }
+ dojo.widget.Editor2.superclass.destroy.call(this);
+ },
+
+ onDisplayChanged: function(/*Object*/e){
+ dojo.widget.Editor2.superclass.onDisplayChanged.call(this,e);
+ this.updateToolbar();
+ },
+
+ onLoad: function(){
+ try{
+ dojo.widget.Editor2.superclass.onLoad.call(this);
+ }catch(e){ // FIXME: debug why this is throwing errors in IE!
+ dojo.debug(e);
+ }
+ this.editorOnLoad();
+ },
+
+ onFocus: function(){
+ dojo.widget.Editor2.superclass.onFocus.call(this);
+ this.setFocus();
+ },
+
+ //overload to support source editing mode
+ getEditorContent: function(){
+ if(this._inSourceMode){
+ this.replaceEditorContent(this._htmlEditNode.value);
+ }
+ return dojo.widget.Editor2.superclass.getEditorContent.call(this);
+ }
+ /*,
+ // FIXME: probably not needed any more with new design, but need to verify
+ _save: function(e){
+ // FIXME: how should this behave when there's a larger form in play?
+ if(!this.isClosed){
+ dojo.debug("save attempt");
+ if(this.saveUrl.length){
+ var content = {};
+ content[this.saveArgName] = this.getEditorContent();
+ dojo.io.bind({
+ method: this.saveMethod,
+ url: this.saveUrl,
+ content: content
+ });
+ }else{
+ dojo.debug("please set a saveUrl for the editor");
+ }
+ if(this.closeOnSave){
+ this.close(e.getName().toLowerCase() == "save");
+ }
+ }
+ }*/
+ },
+ "html"
+);
\ No newline at end of file
Propchange: jackrabbit/trunk/contrib/jcr-browser/src/main/webapp/dojo/src/widget/Editor2.js
------------------------------------------------------------------------------
svn:eol-style = native