source: Dev/branches/rest-dojo-ui/client/dojox/atom/io/model.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 39.8 KB
Line 
1define([
2        "dojo/_base/kernel",
3        "dojo/_base/declare", // dojo.declare
4         "dojo/_base/lang",
5        "dojo/date/stamp",
6        "dojox/xml/parser"
7], function (dojo, declare, lang, stamp, parser) {
8
9var model = dojo.getObject("dojox.atom.io.model", true);
10
11model._Constants = {
12        //      summary:
13        //              Container for general constants.
14        //      description:
15        //              Container for general constants.
16        "ATOM_URI": "http://www.w3.org/2005/Atom",
17        "ATOM_NS": "http://www.w3.org/2005/Atom",
18        "PURL_NS": "http://purl.org/atom/app#",
19        "APP_NS": "http://www.w3.org/2007/app"
20};
21
22model._actions = {
23        //      summary:
24        //              Container for tag handling functions.
25        //      description:
26        //              Container for tag handling functions.  Each child of this container is
27        //              a handler function for the given type of node. Each accepts two parameters:
28        //      obj:  Object.
29        //                The object to insert data into.
30        //      node: DOM Node.
31        //                The dom node containing the data
32        "link": function(obj,node){
33                if(obj.links === null){obj.links = [];}
34                var link = new model.Link();
35                link.buildFromDom(node);
36                obj.links.push(link);
37        },
38        "author": function(obj,node){
39                if(obj.authors === null){obj.authors = [];}
40                var person = new model.Person("author");
41                person.buildFromDom(node);
42                obj.authors.push(person);
43        },
44        "contributor": function(obj,node){
45                if(obj.contributors === null){obj.contributors = [];}
46                var person = new model.Person("contributor");
47                person.buildFromDom(node);
48                obj.contributors.push(person);
49        },
50        "category": function(obj,node){
51                if(obj.categories === null){obj.categories = [];}
52                var cat = new model.Category();
53                cat.buildFromDom(node);
54                obj.categories.push(cat);
55        },
56        "icon": function(obj,node){
57                obj.icon = parser.textContent(node);
58        },
59        "id": function(obj,node){
60                obj.id = parser.textContent(node);
61        },
62        "rights": function(obj,node){
63                obj.rights = parser.textContent(node);
64        },
65        "subtitle": function(obj,node){
66                var cnt = new model.Content("subtitle");
67                cnt.buildFromDom(node);
68                obj.subtitle = cnt;
69        },
70        "title": function(obj,node){
71                var cnt = new model.Content("title");
72                cnt.buildFromDom(node);
73                obj.title = cnt;
74        },
75        "updated": function(obj,node){
76                obj.updated = model.util.createDate(node);
77        },
78        // Google news
79        "issued": function(obj,node){
80                obj.issued = model.util.createDate(node);
81        },
82        // Google news
83        "modified": function(obj,node){
84                obj.modified = model.util.createDate(node);
85        },
86        "published": function(obj,node){
87                obj.published = model.util.createDate(node);
88        },
89        "entry": function(obj,node){
90                if(obj.entries === null){obj.entries = [];}
91                //The object passed in should be a Feed object, since only feeds can contain Entries
92                var entry = obj.createEntry ? obj.createEntry() : new model.Entry();
93                entry.buildFromDom(node);
94                obj.entries.push(entry);
95        },
96        "content": function(obj, node){
97                var cnt = new model.Content("content");
98                cnt.buildFromDom(node);
99                obj.content = cnt;
100        },
101        "summary": function(obj, node){
102                var summary = new model.Content("summary");
103                summary.buildFromDom(node);
104                obj.summary = summary;
105        },
106
107        "name": function(obj,node){
108                obj.name = parser.textContent(node);
109        },
110        "email" : function(obj,node){
111                obj.email = parser.textContent(node);
112        },
113        "uri" : function(obj,node){
114                obj.uri = parser.textContent(node);
115        },
116        "generator" : function(obj,node){
117                obj.generator = new model.Generator();
118                obj.generator.buildFromDom(node);
119        }
120};
121
122model.util = {
123        createDate: function(/*DOM node*/node){
124                //      summary:
125                //              Utility function to create a date from a DOM node's text content.
126                //      description:
127                //              Utility function to create a date from a DOM node's text content.
128                //
129                //      node:
130                //              The DOM node to inspect.
131                //      returns:
132                //              Date object from a DOM Node containing a ISO-8610 string.
133                var textContent = parser.textContent(node);
134                if(textContent){
135                        return stamp.fromISOString(lang.trim(textContent));
136                }
137                return null;
138        },
139        escapeHtml: function(/*String*/str){
140                //      summary:
141                //              Utility function to escape XML special characters in an HTML string.
142                //      description:
143                //              Utility function to escape XML special characters in an HTML string.
144                //
145                //      str:
146                //              The string to escape
147                //      returns:
148                //              HTML String with special characters (<,>,&, ", etc,) escaped.
149                return str.replace(/&/gm, "&amp;").replace(/</gm, "&lt;").replace(/>/gm, "&gt;").replace(/"/gm, "&quot;")
150                        .replace(/'/gm, "&#39;"); // String
151        },
152        unEscapeHtml: function(/*String*/str){
153                //      summary:
154                //              Utility function to un-escape XML special characters in an HTML string.
155                //      description:
156                //              Utility function to un-escape XML special characters in an HTML string.
157                //
158                //      str:
159                //              The string to un-escape.
160                //      returns:
161                //              HTML String converted back to the normal text (unescaped) characters (<,>,&, ", etc,).
162                return str.replace(/&lt;/gm, "<").replace(/&gt;/gm, ">").replace(/&quot;/gm, "\"")
163                        .replace(/&#39;/gm, "'").replace(/&amp;/gm, "&"); // String
164        },
165        getNodename: function(/*DOM node*/node){
166                //      summary:
167                //              Utility function to get a node name and deal with IE's bad handling of namespaces
168                //              on tag names.
169                //      description:
170                //              Utility function to get a node name and deal with IE's bad handling of namespaces
171                //              on tag names.
172                //
173                //      node:
174                //              The DOM node whose name to retrieve.
175                //      returns:
176                //              String
177                //      The name without namespace prefixes.
178                var name = null;
179                if(node !== null){
180                        name = node.localName ? node.localName: node.nodeName;
181                        if(name !== null){
182                                var nsSep = name.indexOf(":");
183                                if(nsSep !== -1){
184                                        name = name.substring((nsSep + 1), name.length);
185                                }
186                        }
187                }
188                return name;
189        }
190};
191
192model.Node = dojo.declare(/*===== 'dojox.atom.io.model.Node', =====*/ null, {
193        constructor: function(name_space,name, attributes,content, shortNs){
194                this.name_space = name_space;
195                this.name = name;
196                this.attributes = [];
197                if(attributes){
198                        this.attributes = attributes;
199                }
200                this.content = [];
201                this.rawNodes = [];
202                this.textContent = null;
203                if(content){
204                        this.content.push(content);
205                }
206                this.shortNs = shortNs;
207                this._objName = "Node";//for debugging purposes
208                this.nodeType = "Node";
209        },
210        buildFromDom: function(node){
211                this._saveAttributes(node);
212                this.name_space = node.namespaceURI;
213                this.shortNs = node.prefix;
214                this.name = model.util.getNodename(node);
215                for(var x=0; x < node.childNodes.length; x++){
216                        var c = node.childNodes[x];
217                        if(model.util.getNodename(c) != "#text" ){
218                                this.rawNodes.push(c);
219                                var n = new model.Node();
220                                n.buildFromDom(c, true);
221                                this.content.push(n);
222                        }else{
223                                this.content.push(c.nodeValue);
224                        }
225                }
226                this.textContent = parser.textContent(node);
227        },
228        _saveAttributes: function(node){
229                if(!this.attributes){this.attributes = [];}
230                // Work around lack of hasAttributes() in IE
231                var hasAttributes = function(node){
232                        var attrs = node.attributes;
233                        if(attrs === null){return false;}
234                        return (attrs.length !== 0);
235                };
236       
237                if(hasAttributes(node) && this._getAttributeNames){
238                        var names = this._getAttributeNames(node);
239                        if(names && names.length > 0){
240                                for(var x in names){
241                                        var attrib = node.getAttribute(names[x]);
242                                        if(attrib){this.attributes[names[x]] = attrib;}
243                                }
244                        }
245                }
246        },
247        addAttribute: function(name, value){
248                this.attributes[name]=value;
249        },
250        getAttribute: function(name){
251                return this.attributes[name];
252        },
253        //if child objects want their attributes parsed, they should override
254        //to return an array of attrib names
255        _getAttributeNames: function(node){
256                var names = [];
257                for(var i =0; i<node.attributes.length; i++){
258                        names.push(node.attributes[i].nodeName);
259                }
260                return names;
261        },
262        toString: function(){
263                var xml = [];
264                var x;
265                var name = (this.shortNs?this.shortNs+":":'')+this.name;
266                var cdata = (this.name == "#cdata-section");
267                if(cdata){
268                        xml.push("<![CDATA[");
269                        xml.push(this.textContent);
270                        xml.push("]]>");
271                }else{
272                        xml.push("<");
273                        xml.push(name);
274                        if(this.name_space){
275                                xml.push(" xmlns='" + this.name_space + "'");
276                        }
277                        if(this.attributes){
278                                for(x in this.attributes){
279                                        xml.push(" " + x + "='" + this.attributes[x] + "'");
280                                }
281                        }
282                        if(this.content){
283                                xml.push(">");
284                                for(x in this.content){
285                                        xml.push(this.content[x]);
286                                }
287                                xml.push("</" + name + ">\n");
288                        }else{
289                                xml.push("/>\n");
290                        }
291                }
292                return xml.join('');
293        },
294        addContent: function(content){
295                this.content.push(content);
296        }
297});
298//Types are as follows: links: array of Link, authors: array of Person, categories: array of Category
299//contributors: array of Person, ico
300model.AtomItem = dojo.declare(/*===== "dojox.atom.io.model.AtomItem", =====*/ model.Node,{
301         constructor: function(args){
302                this.ATOM_URI = model._Constants.ATOM_URI;
303                this.links = null;                                              //Array of Link
304                this.authors = null;                                    //Array of Person
305                this.categories = null;                                 //Array of Category
306                this.contributors = null;                               //Array of Person
307                this.icon = this.id = this.logo = this.xmlBase = this.rights = null; //String
308                this.subtitle = this.title = null;              //Content
309                this.updated = this.published = null;   //Date
310                // Google news
311                this.issued = this.modified = null;             //Date
312                this.content =  null;                                   //Content
313                this.extensions = null;                                 //Array of Node, non atom based
314                this.entries = null;                                    //Array of Entry
315                this.name_spaces = {};
316                this._objName = "AtomItem";                      //for debugging purposes
317                this.nodeType = "AtomItem";
318        },
319        // summary: Class container for generic Atom items.
320        // description: Class container for generic Atom items.
321        _getAttributeNames: function(){return null;},
322        _accepts: {},
323        accept: function(tag){return Boolean(this._accepts[tag]);},
324        _postBuild: function(){},//child objects can override this if they want to be called after a Dom build
325        buildFromDom: function(node){
326                var i, c, n;
327                for(i=0; i<node.attributes.length; i++){
328                        c = node.attributes.item(i);
329                        n = model.util.getNodename(c);
330                        if(c.prefix == "xmlns" && c.prefix != n){
331                                this.addNamespace(c.nodeValue, n);
332                        }
333                }
334                c = node.childNodes;
335                for(i = 0; i< c.length; i++){
336                        if(c[i].nodeType == 1) {
337                                var name = model.util.getNodename(c[i]);
338                                if(!name){continue;}
339                                if(c[i].namespaceURI != model._Constants.ATOM_NS && name != "#text"){
340                                        if(!this.extensions){this.extensions = [];}
341                                        var extensionNode = new model.Node();
342                                        extensionNode.buildFromDom(c[i]);
343                                        this.extensions.push(extensionNode);
344                                }
345                                if(!this.accept(name.toLowerCase())){
346                                        continue;
347                                }
348                                var fn = model._actions[name];
349                                if(fn) {
350                                        fn(this,c[i]);
351                                }
352                        }
353                }
354                this._saveAttributes(node);
355                if(this._postBuild){this._postBuild();}
356        },
357        addNamespace: function(fullName, shortName){
358                if(fullName && shortName){
359                        this.name_spaces[shortName] = fullName;
360                }
361        },
362        addAuthor: function(/*String*/name, /*String*/email, /*String*/uri){
363                //      summary:
364                //              Function to add in an author to the list of authors.
365                //      description:
366                //              Function to add in an author to the list of authors.
367                //
368                //      name:
369                //              The author's name.
370                //      email:
371                //              The author's e-mail address.
372                //      uri:
373                //              A URI associated with the author.
374                if(!this.authors){this.authors = [];}
375                this.authors.push(new model.Person("author",name,email,uri));
376        },
377        addContributor: function(/*String*/name, /*String*/email, /*String*/uri){
378                //      summary:
379                //              Function to add in an author to the list of authors.
380                //      description:
381                //              Function to add in an author to the list of authors.
382                //
383                //      name:
384                //              The author's name.
385                //      email:
386                //              The author's e-mail address.
387                //      uri:
388                //              A URI associated with the author.
389                if(!this.contributors){this.contributors = [];}
390                this.contributors.push(new model.Person("contributor",name,email,uri));
391        },
392        addLink: function(/*String*/href,/*String*/rel,/*String*/hrefLang,/*String*/title,/*String*/type){
393                //      summary:
394                //              Function to add in a link to the list of links.
395                //      description:
396                //              Function to add in a link to the list of links.
397                //
398                //      href:
399                //              The href.
400                //      rel:
401                //              String
402                //      hrefLang:
403                //              String
404                //      title:
405                //              A title to associate with the link.
406                //      type:
407                //              The type of link is is.
408                if(!this.links){this.links=[];}
409                this.links.push(new model.Link(href,rel,hrefLang,title,type));
410        },
411        removeLink: function(/*String*/href, /*String*/rel){
412                //      summary:
413                //              Function to remove a link from the list of links.
414                //      description:
415                //              Function to remove a link from the list of links.
416                //
417                //      href:
418                //              The href.
419                //      rel:
420                //              String
421                if(!this.links || !lang.isArray(this.links)){return;}
422                var count = 0;
423                for(var i = 0; i < this.links.length; i++){
424                        if((!href || this.links[i].href === href) && (!rel || this.links[i].rel === rel)){
425                                this.links.splice(i,1); count++;
426                        }
427                }
428                return count;
429        },
430        removeBasicLinks: function(){
431                //      summary:
432                //              Function to remove all basic links from the list of links.
433                //      description:
434                //              Function to remove all basic link from the list of links.
435                if(!this.links){return;}
436                var count = 0;
437                for(var i = 0; i < this.links.length; i++){
438                        if(!this.links[i].rel){this.links.splice(i,1); count++; i--;}
439                }
440                return count;
441        },
442        addCategory: function(/*String*/scheme, /*String*/term, /*String*/label){
443                //      summary:
444                //              Function to add in a category to the list of categories.
445                //      description:
446                //              Function to add in a category to the list of categories.
447                //
448                //      scheme:
449                //              String
450                //      term:
451                //              String
452                //      label:
453                //              String
454                if(!this.categories){this.categories = [];}
455                this.categories.push(new model.Category(scheme,term,label));
456        },
457        getCategories: function(/*String*/scheme){
458                //      summary:
459                //              Function to get all categories that match a particular scheme.
460                //      description:
461                //              Function to get all categories that match a particular scheme.
462                //
463                //      scheme:
464                //              String
465                //              The scheme to filter on.
466                if(!scheme){return this.categories;}
467                //If categories belonging to a particular scheme are required, then create a new array containing these
468                var arr = [];
469                for(var x in this.categories){
470                        if(this.categories[x].scheme === scheme){arr.push(this.categories[x]);}
471                }
472                return arr;
473        },
474        removeCategories: function(/*String*/scheme, /*String*/term){
475                //      summary:
476                //              Function to remove all categories that match a particular scheme and term.
477                //      description:
478                //              Function to remove all categories that match a particular scheme and term.
479                //
480                //      scheme:
481                //              The scheme to filter on.
482                //      term:
483                //              The term to filter on.
484                if(!this.categories){return;}
485                var count = 0;
486                for(var i=0; i<this.categories.length; i++){
487                        if((!scheme || this.categories[i].scheme === scheme) && (!term || this.categories[i].term === term)){
488                                this.categories.splice(i, 1); count++; i--;
489                        }
490                }
491                return count;
492        },
493        setTitle: function(/*String*/str, /*String*/type){
494                //      summary:
495                //              Function to set the title of the item.
496                //      description:
497                //              Function to set the title of the item.
498                //
499                //      str:
500                //              The title to set.
501                //      type:
502                //              The type of title format, text, xml, xhtml, etc.
503                if(!str){return;}
504                this.title = new model.Content("title");
505                this.title.value = str;
506                if(type){this.title.type = type;}
507        },
508        addExtension: function(/*String*/name_space,/*String*/name, /*Array*/attributes, /*String*/content, /*String*/shortNS){
509                //      summary:
510                //              Function to add in an extension namespace into the item.
511                //      description:
512                //              Function to add in an extension namespace into the item.
513                //
514                //      name_space:
515                //              The namespace of the extension.
516                //      name:
517                //              The name of the extension
518                //      attributes:
519                //              The attributes associated with the extension.
520                //      content:
521                //              The content of the extension.
522                if(!this.extensions){this.extensions=[];}
523                this.extensions.push(new model.Node(name_space,name,attributes,content, shortNS || "ns"+this.extensions.length));
524        },
525        getExtensions: function(/*String*/name_space, /*String*/name){
526                //      summary:
527                //              Function to get extensions that match a namespace and name.
528                //      description:
529                //              Function to get extensions that match a namespace and name.
530                //
531                //      name_space:
532                //              The namespace of the extension.
533                //      name:
534                //              The name of the extension
535                var arr = [];
536                if(!this.extensions){return arr;}
537                for(var x in this.extensions){
538                        if((this.extensions[x].name_space === name_space || this.extensions[x].shortNs === name_space) && (!name || this.extensions[x].name === name)){
539                                arr.push(this.extensions[x]);
540                        }
541                }
542                return arr;
543        },
544        removeExtensions: function(/*String*/name_space, /*String*/name){
545                //      summary:
546                //              Function to remove extensions that match a namespace and name.
547                //      description:
548                //              Function to remove extensions that match a namespace and name.
549                //
550                //      name_space:
551                //              The namespace of the extension.
552                //      name:
553                //              The name of the extension
554                if(!this.extensions){return;}
555                for(var i=0; i< this.extensions.length; i++){
556                        if((this.extensions[i].name_space == name_space || this.extensions[i].shortNs === name_space) && this.extensions[i].name === name){
557                                this.extensions.splice(i,1);
558                                i--;
559                        }
560                }
561        },
562        destroy: function() {
563                this.links = null;
564                this.authors = null;
565                this.categories = null;
566                this.contributors = null;
567                this.icon = this.id = this.logo = this.xmlBase = this.rights = null;
568                this.subtitle = this.title = null;
569                this.updated = this.published = null;
570                // Google news
571                this.issued = this.modified = null;
572                this.content =  null;
573                this.extensions = null;
574                this.entries = null;
575        }
576});
577
578model.Category = dojo.declare(/*===== "dojox.atom.io.model.Category", =====*/ model.Node,{
579        //      summary:
580        //              Class container for 'Category' types.
581        //      description:
582        //              Class container for 'Category' types.
583        constructor: function(/*String*/scheme, /*String*/term, /*String*/label){
584                this.scheme = scheme; this.term = term; this.label = label;
585                this._objName = "Category";//for debugging
586                this.nodeType = "Category";
587        },
588        _postBuild: function(){},
589        _getAttributeNames: function(){
590                return ["label","scheme","term"];
591        },
592        toString: function(){
593                //      summary:
594                //              Function to construct string form of the category tag, which is an XML structure.
595                //      description:
596                //              Function to construct string form of the category tag, which is an XML structure.
597                var s = [];
598                s.push('<category ');
599                if(this.label){s.push(' label="'+this.label+'" ');}
600                if(this.scheme){s.push(' scheme="'+this.scheme+'" ');}
601                if(this.term){s.push(' term="'+this.term+'" ');}
602                s.push('/>\n');
603                return s.join('');
604        },
605        buildFromDom: function(/*DOM node*/node){
606                //      summary:
607                //              Function to do construction of the Category data from the DOM node containing it.
608                //      description:
609                //              Function to do construction of the Category data from the DOM node containing it.
610                //
611                //      node:
612                //              The DOM node to process for content.
613                this._saveAttributes(node);//just get the attributes from the node
614                this.label = this.attributes.label;
615                this.scheme = this.attributes.scheme;
616                this.term = this.attributes.term;
617                if(this._postBuild){this._postBuild();}
618        }
619});
620
621model.Content = dojo.declare(/*===== "dojox.atom.io.model.Content", =====*/ model.Node,{
622        //      summary:
623        //              Class container for 'Content' types. Such as summary, content, username, and so on types of data.
624        //      description:
625        //              Class container for 'Content' types. Such as summary, content, username, and so on types of data.
626        constructor: function(tagName, value, src, type,xmlLang){
627                this.tagName = tagName; this.value = value; this.src = src; this.type=type; this.xmlLang = xmlLang;
628                this.HTML = "html"; this.TEXT = "text"; this.XHTML = "xhtml"; this.XML="xml";
629                this._useTextContent = "true";
630                this.nodeType = "Content";
631        },
632        _getAttributeNames: function(){return ["type","src"];},
633        _postBuild: function(){},
634        buildFromDom: function(/*DOM node*/node){
635                //      summary:
636                //              Function to do construction of the Content data from the DOM node containing it.
637                //      description:
638                //              Function to do construction of the Content data from the DOM node containing it.
639                //
640                //      node:
641                //              The DOM node to process for content.
642                //Handle checking for XML content as the content type
643                var type = node.getAttribute("type");
644                if(type){
645                        type = type.toLowerCase();
646                        if(type == "xml" || "text/xml"){
647                                type = this.XML;
648                        }
649                }else{
650                        type="text";
651                }
652                if(type === this.XML){
653                        if(node.firstChild){
654                                var i;
655                                this.value = "";
656                                for(i = 0; i < node.childNodes.length; i++){
657                                        var c = node.childNodes[i];
658                                        if(c){
659                                                this.value += parser.innerXML(c);
660                                        }
661                                }
662                        }
663                } else if(node.innerHTML){
664                        this.value = node.innerHTML;
665                }else{
666                        this.value = parser.textContent(node);
667                }
668
669                this._saveAttributes(node);
670
671                if(this.attributes){
672                        this.type = this.attributes.type;
673                        this.scheme = this.attributes.scheme;
674                        this.term = this.attributes.term;
675                }
676                if(!this.type){this.type = "text";}
677
678                //We need to unescape the HTML content here so that it can be displayed correctly when the value is fetched.
679                var lowerType = this.type.toLowerCase();
680                if(lowerType === "html" || lowerType === "text/html" || lowerType === "xhtml" || lowerType === "text/xhtml"){
681                        this.value = this.value?model.util.unEscapeHtml(this.value):"";
682                }
683
684                if(this._postBuild){this._postBuild();}
685        },
686        toString: function(){
687                //      summary:
688                //              Function to construct string form of the content tag, which is an XML structure.
689                //      description:
690                //              Function to construct string form of the content tag, which is an XML structure.
691                var s = [];
692                s.push('<'+this.tagName+' ');
693                if(!this.type){this.type = "text";}
694                if(this.type){s.push(' type="'+this.type+'" ');}
695                if(this.xmlLang){s.push(' xml:lang="'+this.xmlLang+'" ');}
696                if(this.xmlBase){s.push(' xml:base="'+this.xmlBase+'" ');}
697               
698                //all HTML must be escaped
699                if(this.type.toLowerCase() == this.HTML){
700                        s.push('>'+model.util.escapeHtml(this.value)+'</'+this.tagName+'>\n');
701                }else{
702                        s.push('>'+this.value+'</'+this.tagName+'>\n');
703                }
704                var ret = s.join('');
705                return ret;
706        }
707});
708
709model.Link = dojo.declare(/*===== "dojox.atom.io.model.Link", =====*/ model.Node,{
710        //      summary:
711        //              Class container for 'link' types.
712        //      description:
713        //              Class container for 'link' types.
714        constructor: function(href,rel,hrefLang,title,type){
715                this.href = href; this.hrefLang = hrefLang; this.rel = rel; this.title = title;this.type = type;
716                this.nodeType = "Link";
717        },
718        _getAttributeNames: function(){return ["href","jrefLang","rel","title","type"];},
719        _postBuild: function(){},
720        buildFromDom: function(node){
721                //      summary:
722                //              Function to do construction of the link data from the DOM node containing it.
723                //      description:
724                //              Function to do construction of the link data from the DOM node containing it.
725                //
726                //      node:
727                //              The DOM node to process for link data.
728                this._saveAttributes(node);//just get the attributes from the node
729                this.href = this.attributes.href;
730                this.hrefLang = this.attributes.hreflang;
731                this.rel = this.attributes.rel;
732                this.title = this.attributes.title;
733                this.type = this.attributes.type;
734                if(this._postBuild){this._postBuild();}
735        },
736        toString: function(){
737                //      summary:
738                //              Function to construct string form of the link tag, which is an XML structure.
739                //      description:
740                //              Function to construct string form of the link tag, which is an XML structure.
741                var s = [];
742                s.push('<link ');
743                if(this.href){s.push(' href="'+this.href+'" ');}
744                if(this.hrefLang){s.push(' hrefLang="'+this.hrefLang+'" ');}
745                if(this.rel){s.push(' rel="'+this.rel+'" ');}
746                if(this.title){s.push(' title="'+this.title+'" ');}
747                if(this.type){s.push(' type = "'+this.type+'" ');}
748                s.push('/>\n');
749                return s.join('');
750        }
751});
752
753model.Person = dojo.declare(/*===== "dojox.atom.io.model.Person", =====*/ model.Node,{
754        //      summary:
755        //              Class container for 'person' types, such as Author, controbutors, and so on.
756        //      description:
757        //              Class container for 'person' types, such as Author, controbutors, and so on.
758        constructor: function(personType, name, email, uri){
759                this.author = "author";
760                this.contributor = "contributor";
761                if(!personType){
762                        personType = this.author;
763                }
764                this.personType = personType;
765                this.name = name || '';
766                this.email = email || '';
767                this.uri = uri || '';
768                this._objName = "Person";//for debugging
769                this.nodeType = "Person";
770        },
771        _getAttributeNames: function(){return null;},
772        _postBuild: function(){},
773        accept: function(tag){return Boolean(this._accepts[tag]);},
774        buildFromDom: function(node){
775                //      summary:
776                //              Function to do construction of the person data from the DOM node containing it.
777                //      description:
778                //              Function to do construction of the person data from the DOM node containing it.
779                //
780                //      node:
781                //              The DOM node to process for person data.
782                var c = node.childNodes;
783                for(var i = 0; i< c.length; i++){
784                        var name = model.util.getNodename(c[i]);
785                       
786                        if(!name){continue;}
787
788                        if(c[i].namespaceURI != model._Constants.ATOM_NS && name != "#text"){
789                                if(!this.extensions){this.extensions = [];}
790                                var extensionNode = new model.Node();
791                                extensionNode.buildFromDom(c[i]);
792                                this.extensions.push(extensionNode);
793                        }
794                        if(!this.accept(name.toLowerCase())){
795                                continue;
796                        }
797                        var fn = model._actions[name];
798                        if(fn) {
799                                fn(this,c[i]);
800                        }
801                }
802                this._saveAttributes(node);
803                if(this._postBuild){this._postBuild();}
804        },
805        _accepts: {
806                'name': true,
807                'uri': true,
808                'email': true
809        },
810        toString: function(){
811                //      summary:
812                //              Function to construct string form of the Person tag, which is an XML structure.
813                //      description:
814                //              Function to construct string form of the Person tag, which is an XML structure.
815                var s = [];
816                s.push('<'+this.personType+'>\n');
817                if(this.name){s.push('\t<name>'+this.name+'</name>\n');}
818                if(this.email){s.push('\t<email>'+this.email+'</email>\n');}
819                if(this.uri){s.push('\t<uri>'+this.uri+'</uri>\n');}
820                s.push('</'+this.personType+'>\n');
821                return s.join('');
822        }
823});
824
825model.Generator = dojo.declare(/*===== "dojox.atom.io.model.Generator", =====*/ model.Node,{
826        //      summary:
827        //              Class container for 'Generator' types.
828        //      description:
829        //              Class container for 'Generator' types.
830        constructor: function(/*String*/uri, /*String*/version, /*String*/value){
831                this.uri = uri;
832                this.version = version;
833                this.value = value;
834        },
835        _postBuild: function(){},
836        buildFromDom: function(node){
837                //      summary:
838                //              Function to do construction of the generator data from the DOM node containing it.
839                //      description:
840                //              Function to do construction of the generator data from the DOM node containing it.
841                //
842                //      node:
843                //              The DOM node to process for link data.
844
845                this.value = parser.textContent(node);
846                this._saveAttributes(node);
847
848                this.uri = this.attributes.uri;
849                this.version = this.attributes.version;
850
851                if(this._postBuild){this._postBuild();}
852        },
853        toString: function(){
854                //      summary:
855                //              Function to construct string form of the Generator tag, which is an XML structure.
856                //      description:
857                //              Function to construct string form of the Generator tag, which is an XML structure.
858                var s = [];
859                s.push('<generator ');
860                if(this.uri){s.push(' uri="'+this.uri+'" ');}
861                if(this.version){s.push(' version="'+this.version+'" ');}
862                s.push('>'+this.value+'</generator>\n');
863                var ret = s.join('');
864                return ret;
865        }
866});
867
868model.Entry = dojo.declare(/*===== "dojox.atom.io.model.Entry", =====*/ model.AtomItem,{
869        //      summary:
870        //              Class container for 'Entry' types.
871        //      description:
872        //              Class container for 'Entry' types.
873        constructor: function(/*String*/id){
874                this.id = id; this._objName = "Entry"; this.feedUrl = null;
875        },
876        _getAttributeNames: function(){return null;},
877        _accepts: {
878                'author': true,
879                'content': true,
880                'category': true,
881                'contributor': true,
882                'created': true,
883                'id': true,
884                'link': true,
885                'published': true,
886                'rights': true,
887                'summary': true,
888                'title': true,
889                'updated': true,
890                'xmlbase': true,
891                'issued': true,
892                'modified': true
893        },
894        toString: function(amPrimary){
895                //      summary:
896                //              Function to construct string form of the entry tag, which is an XML structure.
897                //      description:
898                //              Function to construct string form of the entry tag, which is an XML structure.
899                var s = [];
900                var i;
901                if(amPrimary){
902                        s.push("<?xml version='1.0' encoding='UTF-8'?>");
903                        s.push("<entry xmlns='"+model._Constants.ATOM_URI+"'");
904                }else{s.push("<entry");}
905                if(this.xmlBase){s.push(' xml:base="'+this.xmlBase+'" ');}
906                for(i in this.name_spaces){s.push(' xmlns:'+i+'="'+this.name_spaces[i]+'"');}
907                s.push('>\n');
908                s.push('<id>' + (this.id ? this.id: '') + '</id>\n');
909                if(this.issued && !this.published){this.published = this.issued;}
910                if(this.published){s.push('<published>'+stamp.toISOString(this.published)+'</published>\n');}
911                if(this.created){s.push('<created>'+stamp.toISOString(this.created)+'</created>\n');}
912                //Google News
913                if(this.issued){s.push('<issued>'+stamp.toISOString(this.issued)+'</issued>\n');}
914
915                //Google News
916                if(this.modified){s.push('<modified>'+stamp.toISOString(this.modified)+'</modified>\n');}
917
918                if(this.modified && !this.updated){this.updated = this.modified;}
919                if(this.updated){s.push('<updated>'+stamp.toISOString(this.updated)+'</updated>\n');}
920                if(this.rights){s.push('<rights>'+this.rights+'</rights>\n');}
921                if(this.title){s.push(this.title.toString());}
922                if(this.summary){s.push(this.summary.toString());}
923                var arrays = [this.authors,this.categories,this.links,this.contributors,this.extensions];
924                for(var x in arrays){
925                        if(arrays[x]){
926                                for(var y in arrays[x]){
927                                        s.push(arrays[x][y]);
928                                }
929                        }
930                }
931                if(this.content){s.push(this.content.toString());}
932                s.push("</entry>\n");
933                return s.join(''); //string
934        },
935        getEditHref: function(){
936                //      summary:
937                //              Function to get the href that allows editing of this feed entry.
938                //      description:
939                //              Function to get the href that allows editing of this feed entry.
940                //
941                //      returns:
942                //              The href that specifies edit capability.
943                if(this.links === null || this.links.length === 0){
944                        return null;
945                }
946                for(var x in this.links){
947                        if(this.links[x].rel && this.links[x].rel == "edit"){
948                                return this.links[x].href; //string
949                        }
950                }
951                return null;
952        },
953        setEditHref: function(url){
954                if(this.links === null){
955                        this.links = [];
956                }
957                for(var x in this.links){
958                        if(this.links[x].rel && this.links[x].rel == "edit"){
959                                this.links[x].href = url;
960                                return;
961                        }
962                }
963                this.addLink(url, 'edit');
964        }
965});
966
967model.Feed = dojo.declare(/*===== "dojox.atom.io.model.Feed", =====*/ model.AtomItem,{
968        //      summary:
969        //              Class container for 'Feed' types.
970        //      description:
971        //              Class container for 'Feed' types.
972        _accepts: {
973                'author': true,
974                'content': true,
975                'category': true,
976                'contributor': true,
977                'created': true,
978                'id': true,
979                'link': true,
980                'published': true,
981                'rights': true,
982                'summary': true,
983                'title': true,
984                'updated': true,
985                'xmlbase': true,
986                'entry': true,
987                'logo': true,
988                'issued': true,
989                'modified': true,
990                'icon': true,
991                'subtitle': true
992        },
993        addEntry: function(/*object*/entry){
994                //      summary:
995                //              Function to add an entry to this feed.
996                //      description:
997                //              Function to add an entry to this feed.
998                //      entry:
999                //              The entry object to add.
1000                if(!entry.id){
1001                        throw new Error("The entry object must be assigned an ID attribute.");
1002                }
1003                if(!this.entries){this.entries = [];}
1004                entry.feedUrl = this.getSelfHref();
1005                this.entries.push(entry);
1006        },
1007        getFirstEntry: function(){
1008                //      summary:
1009                //              Function to get the first entry of the feed.
1010                //      description:
1011                //              Function to get the first entry of the feed.
1012                //
1013                //      returns:
1014                //              The first entry in the feed.
1015                if(!this.entries || this.entries.length === 0){return null;}
1016                return this.entries[0]; //object
1017        },
1018        getEntry: function(/*String*/entryId){
1019                //      summary:
1020                //              Function to get an entry by its id.
1021                //      description:
1022                //              Function to get an entry by its id.
1023                //
1024                //      returns:
1025                //              The entry desired, or null if none.
1026                if(!this.entries){return null;}
1027                for(var x in this.entries){
1028                        if(this.entries[x].id == entryId){
1029                                return this.entries[x];
1030                        }
1031                }
1032                return null;
1033        },
1034        removeEntry: function(/*object*/entry){
1035                //      summary:
1036                //              Function to remove an entry from the list of links.
1037                //      description:
1038                //              Function to remove an entry from the list of links.
1039                //
1040                //      entry:
1041                //              The entry.
1042                if(!this.entries){return;}
1043                var count = 0;
1044                for(var i = 0; i < this.entries.length; i++){
1045                        if(this.entries[i] === entry){
1046                                this.entries.splice(i,1);
1047                                count++;
1048                        }
1049                }
1050                return count;
1051        },
1052        setEntries: function(/*array*/arrayOfEntry){
1053                //      summary:
1054                //              Function to add a set of entries to the feed.
1055                //      description:
1056                //              Function to get an entry by its id.
1057                //
1058                //      arrayOfEntry:
1059                //              An array of entry objects to add to the feed.
1060                for(var x in arrayOfEntry){
1061                        this.addEntry(arrayOfEntry[x]);
1062                }
1063        },
1064        toString: function(){
1065                //      summary:
1066                //              Function to construct string form of the feed tag, which is an XML structure.
1067                //      description:
1068                //              Function to construct string form of the feed tag, which is an XML structure.
1069                var s = [];
1070                var i;
1071                s.push('<?xml version="1.0" encoding="utf-8"?>\n');
1072                s.push('<feed xmlns="'+model._Constants.ATOM_URI+'"');
1073                if(this.xmlBase){s.push(' xml:base="'+this.xmlBase+'"');}
1074                for(i in this.name_spaces){s.push(' xmlns:'+i+'="'+this.name_spaces[i]+'"');}
1075                s.push('>\n');
1076                s.push('<id>' + (this.id ? this.id: '') + '</id>\n');
1077                if(this.title){s.push(this.title);}
1078                if(this.copyright && !this.rights){this.rights = this.copyright;}
1079                if(this.rights){s.push('<rights>' + this.rights + '</rights>\n');}
1080               
1081                // Google news
1082                if(this.issued){s.push('<issued>'+stamp.toISOString(this.issued)+'</issued>\n');}
1083                if(this.modified){s.push('<modified>'+stamp.toISOString(this.modified)+'</modified>\n');}
1084
1085                if(this.modified && !this.updated){this.updated=this.modified;}
1086                if(this.updated){s.push('<updated>'+stamp.toISOString(this.updated)+'</updated>\n');}
1087                if(this.published){s.push('<published>'+stamp.toISOString(this.published)+'</published>\n');}
1088                if(this.icon){s.push('<icon>'+this.icon+'</icon>\n');}
1089                if(this.language){s.push('<language>'+this.language+'</language>\n');}
1090                if(this.logo){s.push('<logo>'+this.logo+'</logo>\n');}
1091                if(this.subtitle){s.push(this.subtitle.toString());}
1092                if(this.tagline){s.push(this.tagline.toString());}
1093                //TODO: need to figure out what to do with xmlBase
1094                var arrays = [this.alternateLinks,this.authors,this.categories,this.contributors,this.otherLinks,this.extensions,this.entries];
1095                for(i in arrays){
1096                        if(arrays[i]){
1097                                for(var x in arrays[i]){
1098                                        s.push(arrays[i][x]);
1099                                }
1100                        }
1101                }
1102                s.push('</feed>');
1103                return s.join('');
1104        },
1105        createEntry: function(){
1106                //      summary:
1107                //              Function to Create a new entry object in the feed.
1108                //      description:
1109                //              Function to Create a new entry object in the feed.
1110                //      returns:
1111                //              An empty entry object in the feed.
1112                var entry = new model.Entry();
1113                entry.feedUrl = this.getSelfHref();
1114                return entry; //object
1115        },
1116        getSelfHref: function(){
1117                //      summary:
1118                //              Function to get the href that refers to this feed.
1119                //      description:
1120                //              Function to get the href that refers to this feed.
1121                //      returns:
1122                //              The href that refers to this feed or null if none.
1123                if(this.links === null || this.links.length === 0){
1124                        return null;
1125                }
1126                for(var x in this.links){
1127                        if(this.links[x].rel && this.links[x].rel == "self"){
1128                                return this.links[x].href; //string
1129                        }
1130                }
1131                return null;
1132        }
1133});
1134
1135model.Service = dojo.declare(/*===== "dojox.atom.io.model.Service", =====*/ model.AtomItem,{
1136        //      summary:
1137        //              Class container for 'Feed' types.
1138        //      description:
1139        //              Class container for 'Feed' types.
1140        constructor: function(href){
1141                this.href = href;
1142        },
1143        //builds a Service document.  each element of this, except for the namespace, is the href of
1144        //a service that the server supports.  Some of the common services are:
1145        //"create-entry" , "user-prefs" , "search-entries" , "edit-template" , "categories"
1146        buildFromDom: function(/*DOM node*/node){
1147                //      summary:
1148                //              Function to do construction of the Service data from the DOM node containing it.
1149                //      description:
1150                //              Function to do construction of the Service data from the DOM node containing it.
1151                //
1152                //      node:
1153                //              The DOM node to process for content.
1154                var i;
1155                this.workspaces = [];
1156                if(node.tagName != "service"){
1157                        // FIXME: Need 0.9 DOM util...
1158                        //node = dojox.xml.parser.firstElement(node,"service");
1159                        //if(!node){return;}
1160                        return;
1161                }
1162                if(node.namespaceURI != model._Constants.PURL_NS && node.namespaceURI != model._Constants.APP_NS){return;}
1163                var ns = node.namespaceURI;
1164                this.name_space = node.namespaceURI;
1165                //find all workspaces, and create them
1166                var workspaces ;
1167                if(typeof(node.getElementsByTagNameNS)!= "undefined"){
1168                        workspaces = node.getElementsByTagNameNS(ns,"workspace");
1169                }else{
1170                        // This block is IE only, which doesn't have a 'getElementsByTagNameNS' function
1171                        workspaces = [];
1172                        var temp = node.getElementsByTagName('workspace');
1173                        for(i=0; i<temp.length; i++){
1174                                if(temp[i].namespaceURI == ns){
1175                                        workspaces.push(temp[i]);
1176                                }
1177                        }
1178                }
1179                if(workspaces && workspaces.length > 0){
1180                        var wkLen = 0;
1181                        var workspace;
1182                        for(i = 0; i< workspaces.length; i++){
1183                                workspace = (typeof(workspaces.item)==="undefined"?workspaces[i]:workspaces.item(i));
1184                                var wkspace = new model.Workspace();
1185                                wkspace.buildFromDom(workspace);
1186                                this.workspaces[wkLen++] = wkspace;
1187                        }
1188                }
1189        },
1190        getCollection: function(/*String*/url){
1191                //      summary:
1192                //              Function to collections that match a specific url.
1193                //      description:
1194                //              Function to collections that match a specific url.
1195                //
1196                //      url:
1197                //              e URL to match collections against.
1198                for(var i=0;i<this.workspaces.length;i++){
1199                        var coll=this.workspaces[i].collections;
1200                        for(var j=0;j<coll.length;j++){
1201                                if(coll[j].href == url){
1202                                        return coll;
1203                                }
1204                        }
1205                }
1206                return null;
1207        }
1208});
1209
1210model.Workspace = dojo.declare(/*===== "dojox.atom.io.model.Workspace", =====*/ model.AtomItem,{
1211        //      summary:
1212        //              Class container for 'Workspace' types.
1213        //      description:
1214        //              Class container for 'Workspace' types.
1215        constructor: function(title){
1216                this.title = title;
1217                this.collections = [];
1218        },
1219
1220        buildFromDom: function(/*DOM node*/node){
1221                //      summary:
1222                //              Function to do construction of the Workspace data from the DOM node containing it.
1223                //      description:
1224                //              Function to do construction of the Workspace data from the DOM node containing it.
1225                //
1226                //      node:
1227                //              The DOM node to process for content.
1228                var name = model.util.getNodename(node);
1229                if(name != "workspace"){return;}
1230                var c = node.childNodes;
1231                var len = 0;
1232                for(var i = 0; i< c.length; i++){
1233                        var child = c[i];
1234                        if(child.nodeType === 1){
1235                                name = model.util.getNodename(child);
1236                                if(child.namespaceURI == model._Constants.PURL_NS || child.namespaceURI == model._Constants.APP_NS){
1237                                        if(name === "collection"){
1238                                                var coll = new model.Collection();
1239                                                coll.buildFromDom(child);
1240                                                this.collections[len++] = coll;
1241                                        }
1242                                }else if(child.namespaceURI === model._Constants.ATOM_NS){
1243                                        if(name === "title"){
1244                                                this.title = parser.textContent(child);
1245                                        }
1246                                }
1247                                //FIXME: Add an extension point so others can impl different namespaces.  For now just
1248                                //ignore unknown namespace tags.
1249                        }
1250                }
1251        }
1252});
1253
1254model.Collection = dojo.declare(/*===== "dojox.atom.io.model.Collection", =====*/ model.AtomItem,{
1255        //      summary:
1256        //              Class container for 'Collection' types.
1257        //      description:
1258        //              Class container for 'Collection' types.
1259        constructor: function(href, title){
1260                this.href = href;
1261                this.title = title;
1262                this.attributes = [];
1263                this.features = [];
1264                this.children = [];
1265                this.memberType = null;
1266                this.id = null;
1267        },
1268
1269        buildFromDom: function(/*DOM node*/node){
1270                //      summary:
1271                //              Function to do construction of the Collection data from the DOM node containing it.
1272                //      description:
1273                //              Function to do construction of the Collection data from the DOM node containing it.
1274                //
1275                //      node:
1276                //              The DOM node to process for content.
1277                this.href = node.getAttribute("href");
1278                var c = node.childNodes;
1279                for(var i = 0; i< c.length; i++){
1280                        var child = c[i];
1281                        if(child.nodeType === 1){
1282                                var name = model.util.getNodename(child);
1283                                if(child.namespaceURI == model._Constants.PURL_NS || child.namespaceURI == model._Constants.APP_NS){
1284                                        if(name === "member-type"){
1285                                                this.memberType = parser.textContent(child);
1286                                        }else if(name == "feature"){//this IF stmt might need some more work
1287                                                if(child.getAttribute("id")){this.features.push(child.getAttribute("id"));}
1288                                        }else{
1289                                                var unknownTypeChild = new model.Node();
1290                                                unknownTypeChild.buildFromDom(child);
1291                                                this.children.push(unknownTypeChild);
1292                                        }
1293                                }else if(child.namespaceURI === model._Constants.ATOM_NS){
1294                                        if(name === "id"){
1295                                                this.id = parser.textContent(child);
1296                                        }else if(name === "title"){
1297                                                this.title = parser.textContent(child);
1298                                        }
1299                                }
1300                        }
1301                }
1302        }
1303});
1304
1305return model;
1306});
Note: See TracBrowser for help on using the repository browser.