├── .gitignore
├── demo
├── downloadify
│ ├── images
│ │ └── download.png
│ ├── media
│ │ └── downloadify.swf
│ ├── LICENSE.txt
│ ├── src
│ │ ├── com
│ │ │ └── dynamicflash
│ │ │ │ └── util
│ │ │ │ ├── tests
│ │ │ │ └── Base64Test.as
│ │ │ │ └── Base64.as
│ │ ├── Downloadify.as
│ │ └── downloadify.js
│ ├── test.html
│ ├── js
│ │ ├── downloadify.min.js
│ │ └── swfobject.js
│ └── README.textile
├── stuff.xml
├── spec.html
├── demo.html
├── jasmine-core
│ ├── jasmine.css
│ └── json2.js
├── excel-issues-test.html
└── text.js
├── Excel
├── Paths.js
├── Drawings
│ ├── Chart.js
│ ├── Drawing.js
│ ├── AbsoluteAnchor.js
│ ├── OneCellAnchor.js
│ ├── TwoCellAnchor.js
│ └── Picture.js
├── Positioning.js
├── ZipWorker.js
├── WorksheetExportWorker.js
├── Drawings.js
├── RelationshipManager.js
├── SharedStrings.js
├── XMLDOM.js
├── util.js
├── Table.js
├── Workbook.js
└── Worksheet.js
├── .gitmodules
├── .jshintrc
├── package.json
├── spec
├── lib
│ └── jasmine-1.3.1
│ │ ├── MIT.LICENSE
│ │ └── jasmine.css
├── Excel
│ ├── XMLDOM.js
│ └── util.js
└── SpecRunner.html
├── License
└── MIT.txt
├── README.md
├── Template
└── BasicReport.js
├── excel-builder.js
└── Gruntfile.js
/.gitignore:
--------------------------------------------------------------------------------
1 | buildtools/index.js
2 | /nbproject/private/
3 | .DS_Store
4 | build
5 | node_modules
6 | jszip.js
7 |
--------------------------------------------------------------------------------
/demo/downloadify/images/download.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/no-problemo/excel-builder.js/master/demo/downloadify/images/download.png
--------------------------------------------------------------------------------
/demo/downloadify/media/downloadify.swf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/no-problemo/excel-builder.js/master/demo/downloadify/media/downloadify.swf
--------------------------------------------------------------------------------
/Excel/Paths.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This is mostly a global spot where all of the relationship managers can get and set
3 | * path information from/to.
4 | * @module Excel/Paths
5 | */
6 | define({});
--------------------------------------------------------------------------------
/Excel/Drawings/Chart.js:
--------------------------------------------------------------------------------
1 | define(['underscore', '../util'], function (_) {
2 | "use strict";
3 | var Chart = function () {
4 |
5 | };
6 | _.extend(Chart.prototype, {
7 |
8 | });
9 | return Chart;
10 | });
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "jszip"]
2 | path = jszip
3 | url = git://github.com/Stuk/jszip.git
4 | [submodule "FileSaver"]
5 | path = FileSaver
6 | url = git://github.com/eligrey/FileSaver.js.git
7 | [submodule "Downloadify"]
8 | path = Downloadify
9 | url = https://github.com/dcneiner/Downloadify
10 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqnull": true,
4 | "eqeqeq": true,
5 | "undef": true,
6 | "unused": true,
7 | "strict": true,
8 | "camelcase": true,
9 | "es3": true,
10 | "forin": true,
11 | "immed": true,
12 | "indent": 4,
13 | "latedef": true,
14 | "newcap": true,
15 | "noempty": true,
16 | "nonbsp": true,
17 | "globals": {
18 | "jQuery": true,
19 | "define": true,
20 | "require": true,
21 | "window": true,
22 | "document": true
23 | }
24 | }
--------------------------------------------------------------------------------
/Excel/Positioning.js:
--------------------------------------------------------------------------------
1 | define([], function () {
2 | "use strict";
3 | return {
4 | /**
5 | * Converts pixel sizes to 'EMU's, which is what Open XML uses.
6 | *
7 | * @todo clean this up. Code borrowed from http://polymathprogrammer.com/2009/10/22/english-metric-units-and-open-xml/,
8 | * but not sure that it's going to be as accurate as it needs to be.
9 | *
10 | * @param int pixels
11 | * @returns int
12 | */
13 | pixelsToEMUs: function (pixels) {
14 | return Math.round(pixels * 914400 / 96);
15 | }
16 | };
17 | });
--------------------------------------------------------------------------------
/Excel/ZipWorker.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | onmessage = function(event) {
4 | if (!event.data || !event.data.ziplib) { return; }
5 |
6 | importScripts(event.data.ziplib);
7 |
8 | var zip = new JSZip();
9 | var files = event.data.files;
10 | for(var path in files) {
11 | var content = files[path];
12 | path = path.substr(1);
13 | zip.file(path, content, {base64: false});
14 | };
15 | postMessage({
16 | base64: !!event.data.base64
17 | });
18 | postMessage({
19 | status: 'done',
20 | data: zip.generate({
21 | base64: !!event.data.base64
22 | })
23 | });
24 | };
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "excel-builder",
3 | "version": "1.0.0",
4 | "description": "An easy way of building Excel files with javascript",
5 | "main": "export.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "https://github.com/stephenliberty/excel-builder.js.git"
12 | },
13 | "keywords": [
14 | "excel",
15 | "javascript"
16 | ],
17 | "author": "Stephen Liberty",
18 | "license": "GPLv3",
19 | "bugs": {
20 | "url": "https://github.com/stephenliberty/excel-builder.js/issues"
21 | },
22 | "homepage": "https://github.com/stephenliberty/excel-builder.js",
23 | "devDependencies": {
24 | "grunt": "~0.4.2",
25 | "grunt-contrib-requirejs": "~0.4.1",
26 | "grunt-contrib-uglify": "*",
27 | "almond": "*",
28 | "grunt-contrib-jshint": "*",
29 | "grunt-contrib-copy": "*"
30 | },
31 | "dependencies": {
32 | "underscore": "~1.6.0",
33 | "jszip": "~2.1.0",
34 | "requirejs": "~2.1.10"
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/spec/lib/jasmine-1.3.1/MIT.LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2011 Pivotal Labs
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/License/MIT.txt:
--------------------------------------------------------------------------------
1 | The MIT License
2 |
3 | Copyright (c) 2009 Stuart Knightley
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/demo/downloadify/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Downloadify: Client Side File Creation
2 | JavaScript + Flash Library
3 |
4 | Copyright (c) 2009 Douglas C. Neiner
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | THE SOFTWARE.
--------------------------------------------------------------------------------
/Excel/WorksheetExportWorker.js:
--------------------------------------------------------------------------------
1 | var requireConfig;
2 | var worksheet;
3 | console = {
4 | log: postMessage
5 | };
6 | start = function(data) {
7 | require(['Worksheet'], function(Worksheet) {
8 | worksheet = new Worksheet();
9 | worksheet.importData(data);
10 | postMessage({status: 'sharedStrings', data: worksheet.collectSharedStrings()});
11 |
12 | });
13 | };
14 |
15 | onmessage = function(event) {
16 | var data = event.data;
17 | if (typeof data == 'object') {
18 | switch (data.instruction) {
19 | case "setup":
20 | requireConfig = data.config;
21 | importScripts(data.requireJsPath);
22 | require.config(requireConfig);
23 | postMessage({status: "ready"});
24 | break;
25 | case "start":
26 | start(data.data);
27 | break;
28 | case "export":
29 | worksheet.setSharedStringCollection({
30 | strings: data.sharedStrings
31 | });
32 | postMessage({status: "finished", data: worksheet.toXML().toString()});
33 | break;
34 | }
35 | }
36 | };
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | excel-builder.js
4 | ================
5 |
6 | A way to build excel files with javascript
7 |
8 | Documentation at http://excelbuilderjs.com/. This includes a 'cookbook' and some
9 | API documentation.
10 |
11 | Building
12 | --------
13 |
14 | Install Grunt:
15 |
16 | npm install -g grunt-cli
17 |
18 | Install dependencies:
19 |
20 | npm install
21 |
22 | Combine & uglify:
23 |
24 | grunt requirejs
25 |
26 | Distributables
27 | ---------------
28 | excel-builder.compiled.js -> All files in the EB package + Underscore
29 |
30 | excel-builder.dist.js -> All files in the EB package + Underscore, with no need for external AMD provider (Web worker will not function in this build).
31 |
32 | Contributing
33 | -------------
34 |
35 | Originally this project was sort of sponsored by a previous company I worked for. Unfortunately now it has no backing, and my time is very limited while I work on side projects to help make ends meet. If you use bountysource or contribute via paypal (to stephen@liberty-irm.com) to open up bounties on issues, it is very, very likely that I will add features and fix issues sooner than later.
36 |
37 | Otherwise, if you have the ability to contribute yourself, please just do so as normal - I'll review and pull changes as they come in as quickly as I can.
38 |
--------------------------------------------------------------------------------
/Excel/Drawings/Drawing.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This is mostly a global spot where all of the relationship managers can get and set
3 | * path information from/to.
4 | * @module Excel/Drawing
5 | */
6 | define([
7 | 'underscore', './AbsoluteAnchor', './OneCellAnchor', './TwoCellAnchor'
8 | ], function (_, AbsoluteAnchor, OneCellAnchor, TwoCellAnchor) {
9 | "use strict";
10 | /**
11 | * @constructor
12 | */
13 | var Drawing = function () {
14 | this.id = _.uniqueId('Drawing');
15 | };
16 |
17 | _.extend(Drawing.prototype, {
18 | /**
19 | *
20 | * @param {String} type Can be 'absoluteAnchor', 'oneCellAnchor', or 'twoCellAnchor'.
21 | * @param {Object} config Shorthand - pass the created anchor coords that can normally be used to construct it.
22 | * @returns {Anchor}
23 | */
24 | createAnchor: function (type, config) {
25 | config = config || {};
26 | config.drawing = this;
27 | switch(type) {
28 | case 'absoluteAnchor':
29 | this.anchor = new AbsoluteAnchor(config);
30 | break;
31 | case 'oneCellAnchor':
32 | this.anchor = new OneCellAnchor(config);
33 | break;
34 | case 'twoCellAnchor':
35 | this.anchor = new TwoCellAnchor(config);
36 | break;
37 | }
38 | return this.anchor;
39 | }
40 | });
41 |
42 | return Drawing;
43 | });
--------------------------------------------------------------------------------
/demo/stuff.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Excel/Drawings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module Excel/Drawings
3 | */
4 | define(['underscore', './RelationshipManager', './util'], function (_, RelationshipManager, util) {
5 | "use strict";
6 | var Drawings = function () {
7 | this.drawings = [];
8 | this.relations = new RelationshipManager();
9 | this.id = _.uniqueId('Drawings');
10 | };
11 |
12 | _.extend(Drawings.prototype, {
13 | /**
14 | * Adds a drawing (more likely a subclass of a Drawing) to the 'Drawings' for a particular worksheet.
15 | *
16 | * @param {Drawing} drawing
17 | * @returns {undefined}
18 | */
19 | addDrawing: function (drawing) {
20 | this.drawings.push(drawing);
21 | },
22 | getCount: function () {
23 | return this.drawings.length;
24 | },
25 | toXML: function () {
26 | var doc = util.createXmlDoc(util.schemas.spreadsheetDrawing, 'xdr:wsDr');
27 | var drawings = doc.documentElement;
28 | drawings.setAttribute('xmlns:xdr', util.schemas.spreadsheetDrawing);
29 | drawings.setAttribute('xmlns:a', util.schemas.drawing);
30 |
31 | for(var i = 0, l = this.drawings.length; i < l; i++) {
32 |
33 | var rId = this.relations.getRelationshipId(this.drawings[i].getMediaData());
34 | if(!rId) {
35 | rId = this.relations.addRelation(this.drawings[i].getMediaData(), this.drawings[i].getMediaType()); //chart
36 | }
37 | this.drawings[i].setRelationshipId(rId);
38 | drawings.appendChild(this.drawings[i].toXML(doc));
39 | }
40 | return doc;
41 | }
42 | });
43 |
44 | return Drawings;
45 | });
--------------------------------------------------------------------------------
/demo/spec.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Jasmine Spec Runner
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
32 |
33 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/Excel/RelationshipManager.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module Excel/RelationshipManager
3 | */
4 | define(['underscore', './util', './Paths'], function (_, util, Paths) {
5 | "use strict";
6 | var RelationshipManager = function () {
7 | this.relations = {};
8 | this.lastId = 1;
9 | };
10 |
11 | _.uniqueId('rId'); //priming
12 |
13 | _.extend(RelationshipManager.prototype, {
14 |
15 | importData: function (data) {
16 | this.relations = data.relations;
17 | this.lastId = data.lastId;
18 | },
19 | exportData: function () {
20 | return {
21 | relations: this.relations,
22 | lastId: this.lastId
23 | };
24 | },
25 |
26 | addRelation: function (object, type) {
27 | this.relations[object.id] = {
28 | id: _.uniqueId('rId'),
29 | schema: util.schemas[type]
30 | };
31 | return this.relations[object.id].id;
32 | },
33 |
34 | getRelationshipId: function (object) {
35 | return this.relations[object.id] ? this.relations[object.id].id : null;
36 | },
37 |
38 | toXML: function () {
39 | var doc = util.createXmlDoc(util.schemas.relationshipPackage, 'Relationships');
40 | var relationships = doc.documentElement;
41 |
42 | _.each(this.relations, function (data, id) {
43 | var relationship = util.createElement(doc, 'Relationship', [
44 | ['Id', data.id],
45 | ['Type', data.schema],
46 | ['Target', Paths[id]]
47 | ]);
48 | relationships.appendChild(relationship);
49 | });
50 | return doc;
51 | }
52 | });
53 |
54 | return RelationshipManager;
55 | });
--------------------------------------------------------------------------------
/Excel/SharedStrings.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module Excel/SharedStrings
3 | */
4 | define(['underscore', './util'], function (_, util) {
5 | "use strict";
6 | var sharedStrings = function () {
7 | this.strings = {};
8 | this.stringArray = [];
9 | this.id = _.uniqueId('SharedStrings');
10 | };
11 | _.extend(sharedStrings.prototype, {
12 | /**
13 | * Adds a string to the shared string file, and returns the ID of the
14 | * string which can be used to reference it in worksheets.
15 | *
16 | * @param string {String}
17 | * @return int
18 | */
19 | addString: function (string) {
20 | this.strings[string] = this.stringArray.length;
21 | this.stringArray[this.stringArray.length] = string;
22 | return this.strings[string];
23 | },
24 |
25 | exportData: function () {
26 | return this.strings;
27 | },
28 |
29 | toXML: function () {
30 | var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'sst');
31 | var sharedStringTable = doc.documentElement;
32 | this.stringArray.reverse();
33 | var l = this.stringArray.length;
34 | sharedStringTable.setAttribute('count', l);
35 | sharedStringTable.setAttribute('uniqueCount', l);
36 |
37 | var template = doc.createElement('si');
38 | var templateValue = doc.createElement('t');
39 | templateValue.appendChild(doc.createTextNode('--placeholder--'));
40 | template.appendChild(templateValue);
41 | var strings = this.stringArray;
42 |
43 | while (l--) {
44 | var clone = template.cloneNode(true);
45 | clone.firstChild.firstChild.nodeValue = strings[l];
46 | sharedStringTable.appendChild(clone);
47 | }
48 |
49 | return doc;
50 | }
51 | });
52 | return sharedStrings;
53 | });
--------------------------------------------------------------------------------
/Template/BasicReport.js:
--------------------------------------------------------------------------------
1 | define(['../Excel/Workbook', '../Excel/Table'], function (Workbook, Table) {
2 | var Template = function (worksheetConstructorSettings) {
3 | this.workbook = new Workbook();
4 | this.stylesheet = this.workbook.getStyleSheet();
5 |
6 | this.columns = {};
7 |
8 | this.predefinedStyles = {
9 |
10 | };
11 |
12 | this.predefinedFormatters = {
13 | date: this.stylesheet.createSimpleFormatter('date'),
14 | currency: this.stylesheet.createFormat({format: "$ #,##0.00;$ #,##0.00;-", font: {color: "FFE9F50A"}}),
15 | header: this.stylesheet.createFormat({
16 | font: { bold: true, underline: true, color: {theme: 3}},
17 | alignment: {horizontal: 'center'}
18 | })
19 | };
20 |
21 | if(worksheetConstructorSettings != null) {
22 | this.worksheet = this.workbook.createWorksheet(worksheetConstructorSettings);
23 | }
24 | else {
25 | this.worksheet = this.workbook.createWorksheet();
26 | }
27 | this.workbook.addWorksheet(this.worksheet);
28 | this.worksheet.setPageOrientation('landscape');
29 | this.table = new Table();
30 | this.table.styleInfo.themeStyle = "TableStyleLight1";
31 | this.worksheet.addTable(this.table);
32 | this.workbook.addTable(this.table);
33 | }
34 | $.extend(true, Template.prototype, {
35 | setHeader: function () {
36 | this.worksheet.setHeader.apply(this.worksheet, arguments);
37 | },
38 | setFooter: function () {
39 | this.worksheet.setFooter.apply(this.worksheet, arguments);
40 | },
41 | prepare: function () {
42 | return this.workbook;
43 | },
44 |
45 | setData: function (worksheetData) {
46 | this.worksheet.setData(worksheetData);
47 | this.data = worksheetData;
48 | this.table.setReferenceRange([1, 1], [this.columns.length, worksheetData.length]);
49 | },
50 |
51 | setColumns: function (columns) {
52 | this.columns = columns;
53 | this.worksheet.setColumns(columns);
54 | this.table.setTableColumns(columns);
55 | this.table.setReferenceRange([1, 1], [this.columns.length, this.data.length]);
56 | },
57 |
58 | getWorksheet: function () {
59 | return this.worksheet;
60 | }
61 | });
62 | return Template;
63 | });
64 |
--------------------------------------------------------------------------------
/Excel/Drawings/AbsoluteAnchor.js:
--------------------------------------------------------------------------------
1 | define(['underscore', '../util'], function (_, util) {
2 | "use strict";
3 | /**
4 | *
5 | * @param {Object} config
6 | * @param {Number} config.x X offset in EMU's
7 | * @param {Number} config.y Y offset in EMU's
8 | * @param {Number} config.width Width in EMU's
9 | * @param {Number} config.height Height in EMU's
10 | * @constructor
11 | */
12 | var AbsoluteAnchor = function (config) {
13 | this.x = null;
14 | this.y = null;
15 | this.width = null;
16 | this.height = null;
17 | if(config) {
18 | this.setPos(config.x, config.y);
19 | this.setDimensions(config.width, config.height);
20 | }
21 | };
22 | _.extend(AbsoluteAnchor.prototype, {
23 | /**
24 | * Sets the X and Y offsets.
25 | *
26 | * @param {Number} x
27 | * @param {Number} y
28 | * @returns {undefined}
29 | */
30 | setPos: function (x, y) {
31 | this.x = x;
32 | this.y = y;
33 | },
34 | /**
35 | * Sets the width and height of the image.
36 | *
37 | * @param {Number} width
38 | * @param {Number} height
39 | * @returns {undefined}
40 | */
41 | setDimensions: function (width, height) {
42 | this.width = width;
43 | this.height = height;
44 | },
45 | toXML: function (xmlDoc, content) {
46 | var root = util.createElement(xmlDoc, 'xdr:absoluteAnchor');
47 | var pos = util.createElement(xmlDoc, 'xdr:pos');
48 | pos.setAttribute('x', this.x);
49 | pos.setAttribute('y', this.y);
50 | root.appendChild(pos);
51 |
52 | var dimensions = util.createElement(xmlDoc, 'xdr:ext');
53 | dimensions.setAttribute('cx', this.width);
54 | dimensions.setAttribute('cy', this.height);
55 | root.appendChild(dimensions);
56 |
57 | root.appendChild(content);
58 |
59 | root.appendChild(util.createElement(xmlDoc, 'xdr:clientData'));
60 | return root;
61 | }
62 | });
63 | return AbsoluteAnchor;
64 | });
--------------------------------------------------------------------------------
/spec/Excel/XMLDOM.js:
--------------------------------------------------------------------------------
1 | define(['Excel/XMLDOM'], function(XMLDOM) {
2 | describe("basic DOM simulator for web workers", function() {
3 |
4 | describe("XMLDOM", function() {
5 | var nodeName = "arbitraryNodeName";
6 | var ns = "arbitraryNS";
7 | it("has a documentElement", function () {
8 | var d = new XMLDOM(ns, nodeName);
9 | expect(d.documentElement).toBeTruthy();
10 | });
11 |
12 | it("will have a properly named root node", function () {
13 | var d = new XMLDOM(ns, nodeName);
14 | expect(d.documentElement.nodeName).toEqual(nodeName);
15 | });
16 |
17 | it("will have the correct namespace", function () {
18 | var d = new XMLDOM(ns, nodeName);
19 | expect(d.documentElement.xmlns).toEqual(ns);
20 | });
21 |
22 | it("will have the appropriate content", function () {
23 | var d = new XMLDOM(ns, nodeName);
24 | console.log(d);
25 | var foo = d.createElement('foo');
26 | foo.setAttribute("france", "silly");
27 | foo.setAttribute("britain", "port");
28 | var bar = d.createElement('bar');
29 | bar.setAttribute("georgia", "peaches");
30 | var baz = d.createElement('baz');
31 | foo.appendChild(bar);
32 | d.documentElement.appendChild(foo);
33 | d.documentElement.appendChild(baz);
34 |
35 | console.log(d.toXmlString());
36 | });
37 |
38 | });
39 |
40 | describe("XMLDOM.XMLNode", function() {
41 | var nodeName = "arbitraryNodeName";
42 | var ns = "arbitraryNS";
43 |
44 | it("will clone properly", function () {
45 | var d = new XMLDOM(ns, nodeName);
46 | var foo = d.createElement('foo');
47 | var bar = d.createElement('bar');
48 |
49 | foo.appendChild(bar);
50 |
51 | var baz = foo.cloneNode(true);
52 | bar.setAttribute('joy', true);
53 |
54 | expect(baz.joy).toEqual(undefined);
55 | });
56 |
57 | });
58 |
59 |
60 |
61 | });
62 |
63 | });
--------------------------------------------------------------------------------
/spec/Excel/util.js:
--------------------------------------------------------------------------------
1 | define(['Excel/util'], function(util) {
2 | describe("utility functions", function() {
3 | describe("compilePageDetailPiece", function() {
4 | it("will give back the appropriate string for an instruction object", function() {
5 | var io = {text: "Hello there"};
6 | var text = util.compilePageDetailPiece(io);
7 | var expected = '&"-,Regular"Hello there';
8 | expect(text).toEqual(expected);
9 | });
10 |
11 | it("will give back a string with underline instructions when an instruction object has underline set", function() {
12 | var io = {text: "Hello there", underline: true};
13 | var text = util.compilePageDetailPiece(io);
14 | var expected = '&"-,Regular"&UHello there';
15 | expect(text).toEqual(expected);
16 | });
17 |
18 | it("will give back a string with bold instructions when an instruction object has bold set", function() {
19 | var io = {text: "Hello there", bold: true};
20 | var text = util.compilePageDetailPiece(io);
21 | var expected = '&"-,Bold"Hello there';
22 | expect(text).toEqual(expected);
23 | });
24 |
25 | it("will give back a string with font instructions when an instruction object has a font set", function() {
26 | var io = {text: "Hello there", font: 'Arial'};
27 | var text = util.compilePageDetailPiece(io);
28 | var expected = '&"Arial,Regular"Hello there';
29 | expect(text).toEqual(expected);
30 | });
31 |
32 | it("will build each piece of an array of instructions and return the end result", function() {
33 | var io = [{text: "Hello there", font: 'Arial'}, " - on ", {text: "5/7/9", underline: true}];
34 | var text = util.compilePageDetailPiece(io);
35 | var expected = '&"Arial,Regular"Hello there&"-,Regular" - on &"-,Regular"&U5/7/9';
36 | expect(text).toEqual(expected);
37 | });
38 | });
39 | describe("positionToLetterRef", function() {
40 | it("will give back the appropriate excel cell coordinate on an x/y position", function() {
41 | expect(util.positionToLetterRef(1,1)).toEqual('A1');
42 | expect(util.positionToLetterRef(5,50)).toEqual('E50');
43 | expect(util.positionToLetterRef(50,50)).toEqual('AX50');
44 | });
45 | });
46 | });
47 | });
--------------------------------------------------------------------------------
/demo/downloadify/src/com/dynamicflash/util/tests/Base64Test.as:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright (c) 2006 Steve Webster
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy of
5 | this software and associated documentation files (the "Software"), to deal in
6 | the Software without restriction, including without limitation the rights to
7 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 | the Software, and to permit persons to whom the Software is furnished to do so,
9 | subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 | */
21 |
22 | package com.dynamicflash.util.tests {
23 |
24 | import flexunit.framework.TestCase;
25 | import flexunit.framework.TestSuite;
26 | import flash.utils.ByteArray;
27 |
28 | import com.dynamicflash.util.Base64;
29 |
30 | public class Base64Test extends TestCase {
31 |
32 | public function Base64Test(methodName:String = null) {
33 | super(methodName);
34 | }
35 |
36 | public function testEncode():void {
37 | assertEquals("VGhpcyBpcyBhIHRlc3Q=",Base64.encode("This is a test"));
38 | }
39 |
40 | public function testEncodeDecodeBytes():void {
41 | var obj:Object = {name:"Dynamic Flash", url:"http://dynamicflash.com"};
42 | var source:ByteArray = new ByteArray();
43 | source.writeObject(obj);
44 | var encoded:String = Base64.encodeByteArray(source);
45 | var decoded:ByteArray = Base64.decodeToByteArray(encoded);
46 | var obj2:Object = decoded.readObject();
47 | assertEquals(obj.name, obj2.name);
48 | assertEquals(obj.url, obj2.url);
49 | }
50 |
51 | public function testDecode():void {
52 | assertEquals("This is a test",Base64.decode("VGhpcyBpcyBhIHRlc3Q="));
53 | }
54 |
55 | public function testEncodeDecode():void {
56 | var string:String = "The quick brown fox jumped over the lazy dogs";
57 | assertEquals(string, Base64.decode(Base64.encode(string)));
58 | }
59 | }
60 | }
--------------------------------------------------------------------------------
/Excel/Drawings/OneCellAnchor.js:
--------------------------------------------------------------------------------
1 | define(['underscore', '../util'], function (_, util) {
2 | "use strict";
3 | /**
4 | *
5 | * @param {Object} config
6 | * @param {Number} config.x The cell column number that the top left of the picture will start in
7 | * @param {Number} config.y The cell row number that the top left of the picture will start in
8 | * @param {Number} config.width Width in EMU's
9 | * @param {Number} config.height Height in EMU's
10 | * @constructor
11 | */
12 | var OneCellAnchor = function (config) {
13 | this.x = null;
14 | this.y = null;
15 | this.xOff = null;
16 | this.yOff = null;
17 | this.width = null;
18 | this.height = null;
19 | if(config) {
20 | this.setPos(config.x, config.y, config.xOff, config.yOff);
21 | this.setDimensions(config.width, config.height);
22 | }
23 | };
24 | _.extend(OneCellAnchor.prototype, {
25 | setPos: function (x, y, xOff, yOff) {
26 | this.x = x;
27 | this.y = y;
28 | if(xOff !== undefined) {
29 | this.xOff = xOff;
30 | }
31 | if(yOff !== undefined) {
32 | this.yOff = yOff;
33 | }
34 | },
35 | setDimensions: function (width, height) {
36 | this.width = width;
37 | this.height = height;
38 | },
39 | toXML: function (xmlDoc, content) {
40 | var root = util.createElement(xmlDoc, 'xdr:oneCellAnchor');
41 | var from = util.createElement(xmlDoc, 'xdr:from');
42 | var fromCol = util.createElement(xmlDoc, 'xdr:col');
43 | fromCol.appendChild(xmlDoc.createTextNode(this.x));
44 | var fromColOff = util.createElement(xmlDoc, 'xdr:colOff');
45 | fromColOff.appendChild(xmlDoc.createTextNode(this.xOff || 0));
46 | var fromRow = util.createElement(xmlDoc, 'xdr:row');
47 | fromRow.appendChild(xmlDoc.createTextNode(this.y));
48 | var fromRowOff = util.createElement(xmlDoc, 'xdr:rowOff');
49 | fromRowOff.appendChild(xmlDoc.createTextNode(this.yOff || 0));
50 | from.appendChild(fromCol);
51 | from.appendChild(fromColOff);
52 | from.appendChild(fromRow);
53 | from.appendChild(fromRowOff);
54 |
55 | root.appendChild(from);
56 |
57 | var dimensions = util.createElement(xmlDoc, 'xdr:ext');
58 | dimensions.setAttribute('cx', this.width);
59 | dimensions.setAttribute('cy', this.height);
60 | root.appendChild(dimensions);
61 |
62 | root.appendChild(content);
63 |
64 | root.appendChild(util.createElement(xmlDoc, 'xdr:clientData'));
65 | return root;
66 | }
67 | });
68 | return OneCellAnchor;
69 | });
--------------------------------------------------------------------------------
/spec/SpecRunner.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 | Jasmine Spec Runner
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/Excel/Drawings/TwoCellAnchor.js:
--------------------------------------------------------------------------------
1 | define(['underscore', '../util'], function (_, util) {
2 | 'use strict';
3 | var TwoCellAnchor = function (config) {
4 | this.from = {xOff: 0, yOff: 0};
5 | this.to = {xOff: 0, yOff: 0};
6 | if(config) {
7 | this.setFrom(config.from.x, config.from.y, config.to.xOff, config.to.yOff);
8 | this.setTo(config.to.x, config.to.y, config.to.xOff, config.to.yOff);
9 | }
10 | };
11 | _.extend(TwoCellAnchor.prototype, {
12 | setFrom: function (x, y, xOff, yOff) {
13 | this.from.x = x;
14 | this.from.y = y;
15 | if(xOff !== undefined) {
16 | this.from.xOff = xOff;
17 | }
18 | if(yOff !== undefined) {
19 | this.from.yOff = xOff;
20 | }
21 | },
22 | setTo: function (x, y, xOff, yOff) {
23 | this.to.x = x;
24 | this.to.y = y;
25 | if(xOff !== undefined) {
26 | this.to.xOff = xOff;
27 | }
28 | if(yOff !== undefined) {
29 | this.to.yOff = xOff;
30 | }
31 | },
32 | toXML: function (xmlDoc, content) {
33 | var root = util.createElement(xmlDoc, 'xdr:twoCellAnchor');
34 |
35 | var from = util.createElement(xmlDoc, 'xdr:from');
36 | var fromCol = util.createElement(xmlDoc, 'xdr:col');
37 | fromCol.appendChild(xmlDoc.createTextNode(this.from.x));
38 | var fromColOff = util.createElement(xmlDoc, 'xdr:colOff');
39 | fromColOff.appendChild(xmlDoc.createTextNode(this.from.xOff));
40 | var fromRow = util.createElement(xmlDoc, 'xdr:row');
41 | fromRow.appendChild(xmlDoc.createTextNode(this.from.y));
42 | var fromRowOff = util.createElement(xmlDoc, 'xdr:rowOff');
43 | fromRowOff.appendChild(xmlDoc.createTextNode(this.from.yOff));
44 |
45 | from.appendChild(fromCol);
46 | from.appendChild(fromColOff);
47 | from.appendChild(fromRow);
48 | from.appendChild(fromRowOff);
49 |
50 | var to = util.createElement(xmlDoc, 'xdr:to');
51 | var toCol = util.createElement(xmlDoc, 'xdr:col');
52 | toCol.appendChild(xmlDoc.createTextNode(this.to.x));
53 | var toColOff = util.createElement(xmlDoc, 'xdr:colOff');
54 | toColOff.appendChild(xmlDoc.createTextNode(this.from.xOff));
55 | var toRow = util.createElement(xmlDoc, 'xdr:row');
56 | toRow.appendChild(xmlDoc.createTextNode(this.to.y));
57 | var toRowOff = util.createElement(xmlDoc, 'xdr:rowOff');
58 | toRowOff.appendChild(xmlDoc.createTextNode(this.from.yOff));
59 |
60 | to.appendChild(toCol);
61 | to.appendChild(toColOff);
62 | to.appendChild(toRow);
63 | to.appendChild(toRowOff);
64 |
65 |
66 | root.appendChild(from);
67 | root.appendChild(to);
68 |
69 | root.appendChild(content);
70 |
71 | root.appendChild(util.createElement(xmlDoc, 'xdr:clientData'));
72 | return root;
73 | }
74 | });
75 | return TwoCellAnchor;
76 | });
--------------------------------------------------------------------------------
/excel-builder.js:
--------------------------------------------------------------------------------
1 | define([
2 | 'require',
3 | 'underscore',
4 | './Excel/Workbook',
5 | 'JSZip'
6 | ], function (require, _, Workbook, JSZip) {
7 |
8 | /**
9 | * @name Excel
10 | * @public
11 | * @author Stephen Liberty
12 | * @requires underscore
13 | * @requires Excel/Workbook
14 | * @requires JSZIP
15 | * @exports excel-builder
16 | */
17 | var Factory = {
18 | /**
19 | * Creates a new workbook.
20 | */
21 | createWorkbook: function () {
22 | return new Workbook();
23 | },
24 |
25 | /**
26 | * Turns a workbook into a downloadable file.
27 | * @param {Excel/Workbook} workbook The workbook that is being converted
28 | * @param {Object} options
29 | * @param {Boolean} options.base64 Whether to 'return' the generated file as a base64 string
30 | * @param {Function} options.success The callback function to run after workbook creation is successful.
31 | * @param {Function} options.error The callback function to run if there is an error creating the workbook.
32 | * @param {String} options.requireJsPath (Optional) The path to requirejs. Will use the id 'requirejs' to look up the script if not specified.
33 | */
34 | createFileAsync: function (workbook, options) {
35 |
36 |
37 | workbook.generateFilesAsync({
38 | success: function (files) {
39 |
40 | var worker = new Worker(require.toUrl('./Excel/ZipWorker.js'));
41 | worker.addEventListener('message', function(event, data) {
42 | if(event.data.status == 'done') {
43 | options.success(event.data.data);
44 | }
45 | });
46 | worker.postMessage({
47 | files: files,
48 | ziplib: require.toUrl('JSZip'),
49 | base64: (!options || options.base64 !== false)
50 | });
51 | },
52 | error: function () {
53 | options.error();
54 | }
55 | });
56 | },
57 |
58 | /**
59 | * Turns a workbook into a downloadable file.
60 | * @param {Excel/Workbook} workbook The workbook that is being converted
61 | * @param {Object} options - options to modify how the zip is created. See http://stuk.github.io/jszip/#doc_generate_options
62 | */
63 | createFile: function (workbook, options) {
64 | var zip = new JSZip();
65 | var files = workbook.generateFiles();
66 | _.each(files, function (content, path) {
67 | path = path.substr(1);
68 | if(path.indexOf('.xml') !== -1 || path.indexOf('.rel') !== -1) {
69 | zip.file(path, content, {base64: false});
70 | } else {
71 | zip.file(path, content, {base64: true, binary: true});
72 | }
73 | })
74 | return zip.generate(_.defaults(options || {}, {
75 | type: "base64"
76 | }));
77 | }
78 | }
79 |
80 |
81 | return Factory;
82 | });
--------------------------------------------------------------------------------
/demo/downloadify/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Downloadify
5 |
14 |
15 |
16 |
17 |
18 | Downloadify Example
19 | More info available at the Github Project Page
20 |
34 |
35 |
56 | Downloadify Invoke Script For This Page
57 |
58 | Downloadify.create('downloadify',{
59 | filename: function(){
60 | return document.getElementById('filename').value;
61 | },
62 | data: function(){
63 | return document.getElementById('data').value;
64 | },
65 | onComplete: function(){
66 | alert('Your File Has Been Saved!');
67 | },
68 | onCancel: function(){
69 | alert('You have cancelled the saving of this file.');
70 | },
71 | onError: function(){
72 | alert('You must put something in the File Contents or there will be nothing to save!');
73 | },
74 | swf: 'media/downloadify.swf',
75 | downloadImage: 'images/download.png',
76 | width: 100,
77 | height: 30,
78 | transparent: true,
79 | append: false
80 | });
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/demo/downloadify/js/downloadify.min.js:
--------------------------------------------------------------------------------
1 | /* Downloadify 0.2 (c) 2009 by Douglas Neiner. Licensed under the MIT license */
2 | /* See http://github.com/dcneiner/Downloadify for license and more info */
3 | (function(){Downloadify=window.Downloadify={queue:{},uid:new Date().getTime(),getTextForSave:function(a){var b=Downloadify.queue[a];if(b)return b.getData();return""},getFileNameForSave:function(a){var b=Downloadify.queue[a];if(b)return b.getFilename();return""},getDataTypeForSave:function(a){var b=Downloadify.queue[a];if(b)return b.getDataType();return""},saveComplete:function(a){var b=Downloadify.queue[a];if(b)b.complete();return true},saveCancel:function(a){var b=Downloadify.queue[a];if(b)b.cancel();return true},saveError:function(a){var b=Downloadify.queue[a];if(b)b.error();return true},addToQueue:function(a){Downloadify.queue[a.queue_name]=a},getUID:function(a){if(a.id=="")a.id='downloadify_'+Downloadify.uid++;return a.id}};Downloadify.create=function(a,b){var c=(typeof(a)=="string"?document.getElementById(a):a);return new Downloadify.Container(c,b)};Downloadify.Container=function(d,e){var f=this;f.el=d;f.enabled=true;f.dataCallback=null;f.filenameCallback=null;f.data=null;f.filename=null;var g=function(){f.options=e;if(!f.options.append)f.el.innerHTML="";f.flashContainer=document.createElement('span');f.el.appendChild(f.flashContainer);f.queue_name=Downloadify.getUID(f.flashContainer);if(typeof(f.options.filename)==="function")f.filenameCallback=f.options.filename;else if(f.options.filename)f.filename=f.options.filename;if(typeof(f.options.data)==="function")f.dataCallback=f.options.data;else if(f.options.data)f.data=f.options.data;var a={queue_name:f.queue_name,width:f.options.width,height:f.options.height};var b={allowScriptAccess:'always'};var c={id:f.flashContainer.id,name:f.flashContainer.id};if(f.options.enabled===false)f.enabled=false;if(f.options.transparent===true)b.wmode="transparent";if(f.options.downloadImage)a.downloadImage=f.options.downloadImage;swfobject.embedSWF(f.options.swf,f.flashContainer.id,f.options.width,f.options.height,"10",null,a,b,c);Downloadify.addToQueue(f)};f.enable=function(){var a=document.getElementById(f.flashContainer.id);a.setEnabled(true);f.enabled=true};f.disable=function(){var a=document.getElementById(f.flashContainer.id);a.setEnabled(false);f.enabled=false};f.getData=function(){if(!f.enabled)return"";if(f.dataCallback)return f.dataCallback();else if(f.data)return f.data;else return""};f.getFilename=function(){if(f.filenameCallback)return f.filenameCallback();else if(f.filename)return f.filename;else return""};f.getDataType=function(){if(f.options.dataType)return f.options.dataType;return"string"};f.complete=function(){if(typeof(f.options.onComplete)==="function")f.options.onComplete()};f.cancel=function(){if(typeof(f.options.onCancel)==="function")f.options.onCancel()};f.error=function(){if(typeof(f.options.onError)==="function")f.options.onError()};g()};Downloadify.defaultOptions={swf:'media/downloadify.swf',downloadImage:'images/download.png',width:100,height:30,transparent:true,append:false,dataType:"string"}})();if(typeof(jQuery)!="undefined"){(function($){$.fn.downloadify=function(b){return this.each(function(){b=$.extend({},Downloadify.defaultOptions,b);var a=Downloadify.create(this,b);$(this).data('Downloadify',a)})}})(jQuery)};if(typeof(MooTools)!='undefined'){Element.implement({downloadify:function(a){a=$merge(Downloadify.defaultOptions,a);return this.store('Downloadify',Downloadify.create(this,a))}})};
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | var _ = require('underscore');
2 |
3 | module.exports = function(grunt) {
4 |
5 | var compileOptions = {
6 | baseUrl: ".",
7 | name: "buildtools/index",
8 | optimize: "none",
9 | paths: {
10 | "underscore": "node_modules/underscore/underscore",
11 | "JSZip": "jszip"
12 | },
13 | shim: {
14 | "underscore": {
15 | "exports": '_'
16 | }
17 | }
18 | };
19 |
20 | var files = grunt.file.expand({
21 | cwd: './dist',
22 | filter: function (src) {
23 | if(src.indexOf('WorksheetExportWorker') != -1) {
24 | return false;
25 | }
26 | return true;
27 | }
28 | }, '../Excel/**/*.js');
29 | files = files.map(function (filename) {
30 | return filename.replace('.js', '');
31 | })
32 |
33 | files.push('../excel-builder');
34 |
35 | grunt.file.write('./buildtools/index.js', "define(" + JSON.stringify(files) + ", function () {})");
36 |
37 | // Project configuration.
38 | grunt.initConfig({
39 | pkg: grunt.file.readJSON('package.json'),
40 | requirejs: {
41 | compile: {
42 | options: _.defaults({
43 | out: "dist/<%= pkg.name %>.compiled.js"
44 | }, compileOptions)
45 | },
46 | dist: {
47 | options: _.defaults({
48 | wrap: {
49 | startFile: [
50 | './buildtools/start.js',
51 | './node_modules/almond/almond.js'
52 | ],
53 | endFile: [
54 | './buildtools/end.js'
55 | ]
56 | },
57 | out: "dist/<%= pkg.name %>.dist.js"
58 | }, compileOptions)
59 | }
60 | },
61 | copy: {
62 | jzip: {
63 | src: 'node_modules/jszip/dist/jszip.js',
64 | dest: 'jszip.js'
65 | }
66 | },
67 | uglify: {
68 | options: {
69 | compress: {
70 | drop_console: true
71 | }
72 | },
73 | optimize: {
74 | files: {
75 | 'dist/<%= pkg.name %>.compiled.min.js': ['dist/<%= pkg.name %>.compiled.js'],
76 | 'dist/<%= pkg.name %>.dist.min.js': ['dist/<%= pkg.name %>.dist.js']
77 | }
78 | }
79 | },
80 | jshint: {
81 | options: {
82 | jshintrc: true
83 | },
84 | all: {
85 | //http://stackoverflow.com/questions/20695823/grunt-contrib-jshint-ignores-has-no-effect (hence the ! in front of **/*Worker.js
86 | src: ['Excel/**/*.js', '!**/*Worker.js']
87 | }
88 | }
89 | });
90 |
91 |
92 | grunt.loadNpmTasks('grunt-contrib-copy');
93 | grunt.loadNpmTasks('grunt-contrib-requirejs');
94 | grunt.loadNpmTasks('grunt-contrib-jshint');
95 | grunt.loadNpmTasks('grunt-contrib-uglify');
96 |
97 | // Default task(s).
98 | grunt.registerTask('default', ['copy', 'jshint:all', 'requirejs', 'uglify']);
99 | };
100 |
--------------------------------------------------------------------------------
/Excel/Drawings/Picture.js:
--------------------------------------------------------------------------------
1 | define(['./Drawing', 'underscore', '../util'], function (Drawing, _, util) {
2 | "use strict";
3 | var Picture = function () {
4 | this.media = null;
5 | this.id = _.uniqueId('Picture');
6 | this.pictureId = util.uniqueId('Picture');
7 | this.fill = {};
8 | this.mediaData = null;
9 | };
10 | //
11 | Picture.prototype = new Drawing();
12 |
13 | _.extend(Picture.prototype, {
14 | setMedia: function (mediaRef) {
15 | this.mediaData = mediaRef;
16 | },
17 | setDescription: function (description) {
18 | this.description = description;
19 | },
20 | setFillType: function (type) {
21 | this.fill.type = type;
22 | },
23 | setFillConfig: function (config) {
24 | _.extend(this.fill, config);
25 | },
26 | getMediaType: function () {
27 | return 'image';
28 | },
29 | getMediaData: function () {
30 | return this.mediaData;
31 | },
32 | setRelationshipId: function (rId) {
33 | this.mediaData.rId = rId;
34 | },
35 | toXML: function (xmlDoc) {
36 | var pictureNode = util.createElement(xmlDoc, 'xdr:pic');
37 |
38 | var nonVisibleProperties = util.createElement(xmlDoc, 'xdr:nvPicPr');
39 |
40 | var nameProperties = util.createElement(xmlDoc, 'xdr:cNvPr', [
41 | ['id', this.pictureId],
42 | ['name', this.mediaData.fileName],
43 | ['descr', this.description || ""]
44 | ]);
45 | nonVisibleProperties.appendChild(nameProperties);
46 | var nvPicProperties = util.createElement(xmlDoc, 'xdr:cNvPicPr');
47 | nvPicProperties.appendChild(util.createElement(xmlDoc, 'a:picLocks', [
48 | ['noChangeAspect', '1'],
49 | ['noChangeArrowheads', '1']
50 | ]));
51 | nonVisibleProperties.appendChild(nvPicProperties);
52 | pictureNode.appendChild(nonVisibleProperties);
53 | var pictureFill = util.createElement(xmlDoc, 'xdr:blipFill');
54 | pictureFill.appendChild(util.createElement(xmlDoc, 'a:blip', [
55 | ['xmlns:r', util.schemas.relationships],
56 | ['r:embed', this.mediaData.rId]
57 | ]));
58 | pictureFill.appendChild(util.createElement(xmlDoc, 'a:srcRect'));
59 | var stretch = util.createElement(xmlDoc, 'a:stretch');
60 | stretch.appendChild(util.createElement(xmlDoc, 'a:fillRect'));
61 | pictureFill.appendChild(stretch);
62 | pictureNode.appendChild(pictureFill);
63 |
64 | var shapeProperties = util.createElement(xmlDoc, 'xdr:spPr', [
65 | ['bwMode', 'auto']
66 | ]);
67 |
68 | var transform2d = util.createElement(xmlDoc, 'a:xfrm');
69 | shapeProperties.appendChild(transform2d);
70 |
71 | var presetGeometry = util.createElement(xmlDoc, 'a:prstGeom', [
72 | ['prst', 'rect']
73 | ]);
74 | shapeProperties.appendChild(presetGeometry);
75 |
76 |
77 |
78 | pictureNode.appendChild(shapeProperties);
79 | //
80 | //
81 | //
82 | //
83 | //
84 | //
85 | //
86 | //
87 | //
88 | //
89 | //
90 | //
91 | //
92 | //
93 | //
94 | //
95 | //
96 | //
97 | //
98 | //
99 | return this.anchor.toXML(xmlDoc, pictureNode);
100 | }
101 | });
102 | return Picture;
103 | });
--------------------------------------------------------------------------------
/Excel/XMLDOM.js:
--------------------------------------------------------------------------------
1 | define(['underscore'], function (_) {
2 | 'use strict';
3 | var XMLDOM = function (ns, rootNodeName) {
4 | this.documentElement = this.createElement(rootNodeName);
5 | this.documentElement.setAttribute('xmlns', ns);
6 | };
7 |
8 | _.extend(XMLDOM.prototype, {
9 | createElement: function (name) {
10 | return new XMLDOM.XMLNode({
11 | nodeName: name
12 | });
13 | },
14 | createTextNode: function (text) {
15 | return new XMLDOM.TextNode(text);
16 | },
17 | toString: function () {
18 | return this.documentElement.toString();
19 | }
20 | });
21 |
22 | XMLDOM.Node = function () {};
23 | XMLDOM.Node.Create = function (config) {
24 | switch(config.type) {
25 | case "XML":
26 | return new XMLDOM.XMLNode(config);
27 | case "TEXT":
28 | return new XMLDOM.TextNode(config.nodeValue);
29 | }
30 | };
31 |
32 | XMLDOM.TextNode = function (text) {
33 | this.nodeValue = text;
34 | };
35 | _.extend(XMLDOM.TextNode.prototype, {
36 | toJSON: function () {
37 | return {
38 | nodeValue: this.nodeValue,
39 | type: 'TEXT'
40 | };
41 | },
42 | toString: function () {
43 | return _.escape(this.nodeValue);
44 | }
45 | });
46 |
47 | XMLDOM.XMLNode = function (config) {
48 | this.nodeName = config.nodeName;
49 | this.children = [];
50 | this.nodeValue = config.nodeValue || "";
51 | this.attributes = {};
52 |
53 | if(config.children) {
54 | for(var i = 0; i < config.children.length; i++) {
55 | this.appendChild(XMLDOM.Node.Create(config.children[i]));
56 | }
57 | }
58 |
59 | if(config.attributes) {
60 | for(var attr in config.attributes) {
61 | if(config.attributes.hasOwnProperty(attr)) {
62 | this.setAttribute(attr, config.attributes[attr]);
63 | }
64 | }
65 | }
66 | };
67 | _.extend(XMLDOM.XMLNode.prototype, {
68 |
69 | toString: function () {
70 | var string = "<" + this.nodeName;
71 | var attrs = [];
72 | for(var attr in this.attributes) {
73 | if(this.attributes.hasOwnProperty(attr)) {
74 | attrs.push(attr + "=\""+_.escape(this.attributes[attr])+"\"");
75 | }
76 | }
77 | if (attrs.length > 0){
78 | string+= " " + attrs.join(" ");
79 | }
80 |
81 | var childContent = "";
82 | for(var i = 0, l = this.children.length; i < l; i++) {
83 | childContent += this.children[i].toString();
84 | }
85 |
86 | if (childContent){
87 | string += ">" + childContent + "" + this.nodeName + ">";
88 | } else {
89 | string += "/>";
90 | }
91 |
92 | return string;
93 | },
94 |
95 | toJSON: function () {
96 | var children = [];
97 | for(var i = 0, l = this.children.length; i < l; i++) {
98 | children.push(this.children[i].toJSON());
99 | }
100 | return {
101 | nodeName: this.nodeName,
102 | children: children,
103 | nodeValue: this.nodeValue,
104 | attributes: this.attributes,
105 | type: "XML"
106 | };
107 | },
108 |
109 | setAttribute: function (name, val) {
110 | if(val === null) {
111 | delete this.attributes[name];
112 | delete this[name];
113 | return;
114 | }
115 | this.attributes[name] = val;
116 | this[name] = val;
117 | },
118 | setAttributeNS: function (ns, name, val) {
119 | this.setAttribute(name, val);
120 | },
121 | appendChild: function (child) {
122 | this.children.push(child);
123 | this.firstChild = this.children[0];
124 | },
125 | cloneNode: function () {
126 | return new XMLDOM.XMLNode(this.toJSON());
127 | }
128 | });
129 |
130 | return XMLDOM;
131 | });
--------------------------------------------------------------------------------
/demo/downloadify/src/com/dynamicflash/util/Base64.as:
--------------------------------------------------------------------------------
1 | /*
2 | Base64 - 1.1.0
3 |
4 | Copyright (c) 2006 Steve Webster
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of
7 | this software and associated documentation files (the "Software"), to deal in
8 | the Software without restriction, including without limitation the rights to
9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software is furnished to do so,
11 | subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | */
23 |
24 | package com.dynamicflash.util {
25 |
26 | import flash.utils.ByteArray;
27 |
28 | public class Base64 {
29 |
30 | private static const BASE64_CHARS:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
31 |
32 | public static const version:String = "1.1.0";
33 |
34 | public static function encode(data:String):String {
35 | // Convert string to ByteArray
36 | var bytes:ByteArray = new ByteArray();
37 | bytes.writeUTFBytes(data);
38 |
39 | // Return encoded ByteArray
40 | return encodeByteArray(bytes);
41 | }
42 |
43 | public static function encodeByteArray(data:ByteArray):String {
44 | // Initialise output
45 | var output:String = "";
46 |
47 | // Create data and output buffers
48 | var dataBuffer:Array;
49 | var outputBuffer:Array = new Array(4);
50 |
51 | // Rewind ByteArray
52 | data.position = 0;
53 |
54 | // while there are still bytes to be processed
55 | while (data.bytesAvailable > 0) {
56 | // Create new data buffer and populate next 3 bytes from data
57 | dataBuffer = new Array();
58 | for (var i:uint = 0; i < 3 && data.bytesAvailable > 0; i++) {
59 | dataBuffer[i] = data.readUnsignedByte();
60 | }
61 |
62 | // Convert to data buffer Base64 character positions and
63 | // store in output buffer
64 | outputBuffer[0] = (dataBuffer[0] & 0xfc) >> 2;
65 | outputBuffer[1] = ((dataBuffer[0] & 0x03) << 4) | ((dataBuffer[1]) >> 4);
66 | outputBuffer[2] = ((dataBuffer[1] & 0x0f) << 2) | ((dataBuffer[2]) >> 6);
67 | outputBuffer[3] = dataBuffer[2] & 0x3f;
68 |
69 | // If data buffer was short (i.e not 3 characters) then set
70 | // end character indexes in data buffer to index of '=' symbol.
71 | // This is necessary because Base64 data is always a multiple of
72 | // 4 bytes and is basses with '=' symbols.
73 | for (var j:uint = dataBuffer.length; j < 3; j++) {
74 | outputBuffer[j + 1] = 64;
75 | }
76 |
77 | // Loop through output buffer and add Base64 characters to
78 | // encoded data string for each character.
79 | for (var k:uint = 0; k < outputBuffer.length; k++) {
80 | output += BASE64_CHARS.charAt(outputBuffer[k]);
81 | }
82 | }
83 |
84 | // Return encoded data
85 | return output;
86 | }
87 |
88 | public static function decode(data:String):String {
89 | // Decode data to ByteArray
90 | var bytes:ByteArray = decodeToByteArray(data);
91 |
92 | // Convert to string and return
93 | return bytes.readUTFBytes(bytes.length);
94 | }
95 |
96 | public static function decodeToByteArray(data:String):ByteArray {
97 | // Initialise output ByteArray for decoded data
98 | var output:ByteArray = new ByteArray();
99 |
100 | // Create data and output buffers
101 | var dataBuffer:Array = new Array(4);
102 | var outputBuffer:Array = new Array(3);
103 |
104 | // While there are data bytes left to be processed
105 | for (var i:uint = 0; i < data.length; i += 4) {
106 | // Populate data buffer with position of Base64 characters for
107 | // next 4 bytes from encoded data
108 | for (var j:uint = 0; j < 4 && i + j < data.length; j++) {
109 | dataBuffer[j] = BASE64_CHARS.indexOf(data.charAt(i + j));
110 | }
111 |
112 | // Decode data buffer back into bytes
113 | outputBuffer[0] = (dataBuffer[0] << 2) + ((dataBuffer[1] & 0x30) >> 4);
114 | outputBuffer[1] = ((dataBuffer[1] & 0x0f) << 4) + ((dataBuffer[2] & 0x3c) >> 2);
115 | outputBuffer[2] = ((dataBuffer[2] & 0x03) << 6) + dataBuffer[3];
116 |
117 | // Add all non-padded bytes in output buffer to decoded data
118 | for (var k:uint = 0; k < outputBuffer.length; k++) {
119 | if (dataBuffer[k+1] == 64) break;
120 | output.writeByte(outputBuffer[k]);
121 | }
122 | }
123 |
124 | // Rewind decoded data ByteArray
125 | output.position = 0;
126 |
127 | // Return decoded data
128 | return output;
129 | }
130 |
131 | public function Base64() {
132 | throw new Error("Base64 class is static container only");
133 | }
134 | }
135 | }
--------------------------------------------------------------------------------
/Excel/util.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module Excel/util
3 | */
4 | define(['./XMLDOM'], function (XMLDOM) {
5 | "use strict";
6 | var util = {
7 |
8 | _idSpaces: {},
9 |
10 | /**
11 | * Returns a number based on a namespace. So, running with 'Picture' will return 1. Run again, you will get 2. Run with 'Foo', you'll get 1.
12 | * @param {String} space
13 | * @returns {Number}
14 | */
15 | uniqueId: function (space) {
16 | if(!this._idSpaces[space]) {
17 | this._idSpaces[space] = 1;
18 | }
19 | return this._idSpaces[space]++;
20 | },
21 |
22 | /**
23 | * Attempts to create an XML document. Due to limitations in web workers,
24 | * it may return a 'fake' xml document created from the XMLDOM.js file.
25 | *
26 | * Takes a namespace to start the xml file in, as well as the root element
27 | * of the xml file.
28 | *
29 | * @param {type} ns
30 | * @param {type} base
31 | * @returns {ActiveXObject|@exp;document@pro;implementation@call;createDocument|@new;XMLDOM}
32 | */
33 | createXmlDoc: function (ns, base) {
34 | if(typeof document === 'undefined') {
35 | return new XMLDOM(ns || null, base, null);
36 | }
37 | if(document.implementation && document.implementation.createDocument) {
38 | return document.implementation.createDocument(ns || null, base, null);
39 | } else if (window.ActiveXObject) {
40 | var doc = new window.ActiveXObject( "Microsoft.XMLDOM" );
41 | var rootNode = doc.createElement(base);
42 | rootNode.setAttribute('xmlns', ns);
43 | doc.appendChild(rootNode);
44 | return doc;
45 | }
46 | throw "No xml document generator";
47 | },
48 |
49 | /**
50 | * Creates an xml node (element). Used to simplify some calls, as IE is
51 | * very particular about namespaces and such.
52 | *
53 | * @param {XMLDOM} doc An xml document (actual DOM or fake DOM, not a string)
54 | * @param {type} name The name of the element
55 | * @param {type} attributes
56 | * @returns {XML Node}
57 | */
58 | createElement: function (doc, name, attributes) {
59 | var el = doc.createElement(name);
60 | var ie = !el.setAttributeNS;
61 | attributes = attributes || [];
62 | var i = attributes.length;
63 | while (i--) {
64 | if(!ie && attributes[i][0].indexOf('xmlns') !== -1) {
65 | el.setAttributeNS("http://www.w3.org/2000/xmlns/", attributes[i][0], attributes[i][1]);
66 | } else {
67 | el.setAttribute(attributes[i][0], attributes[i][1]);
68 | }
69 | }
70 | return el;
71 | },
72 |
73 | LETTER_REFS: {},
74 |
75 | positionToLetterRef: function (x, y) {
76 | var digit = 1, index, num = x, string = "", alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
77 | if(this.LETTER_REFS[x]) {
78 | return this.LETTER_REFS[x].concat(y);
79 | }
80 | while (num > 0) {
81 | num -= Math.pow(26, digit -1);
82 | index = num % Math.pow(26, digit);
83 | num -= index;
84 | index = index / Math.pow(26, digit - 1);
85 | string = alphabet.charAt(index) + string;
86 | digit += 1;
87 | }
88 | this.LETTER_REFS[x] = string;
89 | return string.concat(y);
90 | },
91 |
92 | schemas: {
93 | 'worksheet': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet',
94 | 'sharedStrings': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings",
95 | 'stylesheet': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles",
96 | 'relationships': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
97 | 'relationshipPackage': "http://schemas.openxmlformats.org/package/2006/relationships",
98 | 'contentTypes': "http://schemas.openxmlformats.org/package/2006/content-types",
99 | 'spreadsheetml': "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
100 | 'markupCompat': "http://schemas.openxmlformats.org/markup-compatibility/2006",
101 | 'x14ac': "http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac",
102 | 'officeDocument': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
103 | 'package': "http://schemas.openxmlformats.org/package/2006/relationships",
104 | 'table': "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
105 | 'spreadsheetDrawing': 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing',
106 | 'drawing': 'http://schemas.openxmlformats.org/drawingml/2006/main',
107 | 'drawingRelationship': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing',
108 | 'image': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',
109 | 'chart': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart'
110 | }
111 | };
112 |
113 | return util;
114 | });
--------------------------------------------------------------------------------
/demo/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Click me!
14 |
15 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/demo/downloadify/src/Downloadify.as:
--------------------------------------------------------------------------------
1 | /*
2 | Downloadify: Client Side File Creation
3 | JavaScript + Flash Library
4 |
5 | Version: 0.2
6 |
7 | Copyright (c) 2009 Douglas C. Neiner
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
26 | */
27 | package {
28 | import flash.system.Security;
29 | import flash.events.Event;
30 | import flash.events.MouseEvent;
31 | import flash.net.FileReference;
32 | import flash.net.FileFilter;
33 | import flash.net.URLRequest;
34 | import flash.display.*;
35 | import flash.utils.ByteArray;
36 | import flash.external.ExternalInterface;
37 | import com.dynamicflash.util.Base64;
38 |
39 | [SWF(backgroundColor="#CCCCCC")]
40 | [SWF(backgroundAlpha=0)]
41 | public class Downloadify extends Sprite {
42 |
43 | private var options:Object,
44 | file:FileReference = new FileReference(),
45 | queue_name:String = "",
46 |
47 | _width:Number = 0,
48 | _height:Number = 0,
49 |
50 | enabled:Boolean = true,
51 | over:Boolean = false,
52 | down:Boolean = false,
53 |
54 | buttonImage:String = "images/download.png",
55 |
56 | button:Loader;
57 |
58 | public function Downloadify() {
59 | Security.allowDomain('*');
60 |
61 | stage.align = StageAlign.TOP_LEFT;
62 | stage.scaleMode = StageScaleMode.NO_SCALE;
63 |
64 | options = this.root.loaderInfo.parameters;
65 |
66 | queue_name = options.queue_name.toString();
67 |
68 | _width = options.width;
69 | _height = options.height;
70 |
71 | if(options.downloadImage){
72 | buttonImage = options.downloadImage;
73 | }
74 |
75 | setupDefaultButton();
76 | addChild(button);
77 |
78 | this.buttonMode = true;
79 |
80 | this.addEventListener(MouseEvent.CLICK, onMouseClickEvent);
81 | this.addEventListener(MouseEvent.ROLL_OVER , onMouseEnter);
82 | this.addEventListener(MouseEvent.ROLL_OUT , onMouseLeave);
83 | this.addEventListener(MouseEvent.MOUSE_DOWN , onMouseDown);
84 | this.addEventListener(MouseEvent.MOUSE_UP , onMouseUp);
85 |
86 | ExternalInterface.addCallback('setEnabled', setEnabled);
87 |
88 | file.addEventListener(Event.COMPLETE, onSaveComplete);
89 | file.addEventListener(Event.CANCEL, onSaveCancel);
90 | }
91 |
92 | private function setEnabled(isEnabled:Boolean):Boolean {
93 | enabled = isEnabled;
94 | if(enabled === true){
95 | button.y = 0;
96 | this.buttonMode = true;
97 | } else {
98 | button.y = (-3 * _height);
99 | this.buttonMode = false;
100 | }
101 | return enabled;
102 | }
103 |
104 | private function setupDefaultButton():void {
105 | button = new Loader();
106 | var urlReq:URLRequest = new URLRequest(buttonImage);
107 | button.load(urlReq);
108 | button.x = 0;
109 | button.y = 0;
110 | }
111 |
112 |
113 |
114 | protected function onMouseEnter(event:Event):void {
115 | if(enabled === true){
116 | if(down === false) button.y = (-1 * _height);
117 | over = true;
118 | }
119 | }
120 | protected function onMouseLeave(event:Event):void {
121 | if(enabled === true){
122 | if(down === false) button.y = 0;
123 | over = false;
124 | }
125 | }
126 | protected function onMouseDown(event:Event):void {
127 | if(enabled === true){
128 | button.y = button.y = (-2 * _height);
129 | down = true;
130 | }
131 | }
132 | protected function onMouseUp(event:Event):void {
133 | if(enabled === true){
134 | if(over === false){
135 | button.y = 0;
136 | } else {
137 | button.y = (-1 * _height);
138 | }
139 | down = false;
140 | }
141 | }
142 |
143 | protected function onMouseClickEvent(event:Event):void{
144 | var theData:String = ExternalInterface.call('Downloadify.getTextForSave',queue_name),
145 | filename:String = ExternalInterface.call('Downloadify.getFileNameForSave',queue_name),
146 | dataType:String = ExternalInterface.call('Downloadify.getDataTypeForSave',queue_name);
147 |
148 | if (dataType == "string" && theData != "") {
149 | file.save(theData, filename);
150 | } else if (dataType == "base64" && theData){
151 | file.save(Base64.decodeToByteArray(theData), filename);
152 | } else {
153 | onSaveError();
154 | }
155 | }
156 |
157 | protected function onSaveComplete(event:Event):void{
158 | trace('Save Complete');
159 | ExternalInterface.call('Downloadify.saveComplete',queue_name);
160 | }
161 |
162 | protected function onSaveCancel(event:Event):void{
163 | trace('Save Cancel');
164 | ExternalInterface.call('Downloadify.saveCancel',queue_name);
165 | }
166 |
167 | protected function onSaveError():void{
168 | trace('Save Error');
169 | ExternalInterface.call('Downloadify.saveError',queue_name);
170 | }
171 |
172 | }
173 | }
--------------------------------------------------------------------------------
/demo/jasmine-core/jasmine.css:
--------------------------------------------------------------------------------
1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
2 |
3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
4 | #HTMLReporter a { text-decoration: none; }
5 | #HTMLReporter a:hover { text-decoration: underline; }
6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; }
9 | #HTMLReporter .version { color: #aaaaaa; }
10 | #HTMLReporter .banner { margin-top: 14px; }
11 | #HTMLReporter .duration { color: #aaaaaa; float: right; }
12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; }
15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; }
17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; }
21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
22 | #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
23 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
24 | #HTMLReporter .runningAlert { background-color: #666666; }
25 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; }
26 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; }
27 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
28 | #HTMLReporter .passingAlert { background-color: #a6b779; }
29 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
30 | #HTMLReporter .failingAlert { background-color: #cf867e; }
31 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; }
32 | #HTMLReporter .results { margin-top: 14px; }
33 | #HTMLReporter #details { display: none; }
34 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
35 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
36 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
37 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
38 | #HTMLReporter.showDetails .summary { display: none; }
39 | #HTMLReporter.showDetails #details { display: block; }
40 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
41 | #HTMLReporter .summary { margin-top: 14px; }
42 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
43 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
44 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; }
45 | #HTMLReporter .description + .suite { margin-top: 0; }
46 | #HTMLReporter .suite { margin-top: 14px; }
47 | #HTMLReporter .suite a { color: #333333; }
48 | #HTMLReporter #details .specDetail { margin-bottom: 28px; }
49 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
50 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
51 | #HTMLReporter .resultMessage span.result { display: block; }
52 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
53 |
54 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
55 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; }
56 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
57 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
58 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
59 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
60 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
61 | #TrivialReporter .runner.running { background-color: yellow; }
62 | #TrivialReporter .options { text-align: right; font-size: .8em; }
63 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
64 | #TrivialReporter .suite .suite { margin: 5px; }
65 | #TrivialReporter .suite.passed { background-color: #dfd; }
66 | #TrivialReporter .suite.failed { background-color: #fdd; }
67 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
68 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
69 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
70 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
71 | #TrivialReporter .spec.skipped { background-color: #bbb; }
72 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
73 | #TrivialReporter .passed { background-color: #cfc; display: none; }
74 | #TrivialReporter .failed { background-color: #fbb; }
75 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
76 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
77 | #TrivialReporter .resultMessage .mismatch { color: black; }
78 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
79 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
80 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
81 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; }
82 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
83 |
--------------------------------------------------------------------------------
/spec/lib/jasmine-1.3.1/jasmine.css:
--------------------------------------------------------------------------------
1 | body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
2 |
3 | #HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
4 | #HTMLReporter a { text-decoration: none; }
5 | #HTMLReporter a:hover { text-decoration: underline; }
6 | #HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
7 | #HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
8 | #HTMLReporter #jasmine_content { position: fixed; right: 100%; }
9 | #HTMLReporter .version { color: #aaaaaa; }
10 | #HTMLReporter .banner { margin-top: 14px; }
11 | #HTMLReporter .duration { color: #aaaaaa; float: right; }
12 | #HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
13 | #HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
14 | #HTMLReporter .symbolSummary li.passed { font-size: 14px; }
15 | #HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
16 | #HTMLReporter .symbolSummary li.failed { line-height: 9px; }
17 | #HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
18 | #HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
19 | #HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
20 | #HTMLReporter .symbolSummary li.pending { line-height: 11px; }
21 | #HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
22 | #HTMLReporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
23 | #HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
24 | #HTMLReporter .runningAlert { background-color: #666666; }
25 | #HTMLReporter .skippedAlert { background-color: #aaaaaa; }
26 | #HTMLReporter .skippedAlert:first-child { background-color: #333333; }
27 | #HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
28 | #HTMLReporter .passingAlert { background-color: #a6b779; }
29 | #HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
30 | #HTMLReporter .failingAlert { background-color: #cf867e; }
31 | #HTMLReporter .failingAlert:first-child { background-color: #b03911; }
32 | #HTMLReporter .results { margin-top: 14px; }
33 | #HTMLReporter #details { display: none; }
34 | #HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
35 | #HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
36 | #HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
37 | #HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
38 | #HTMLReporter.showDetails .summary { display: none; }
39 | #HTMLReporter.showDetails #details { display: block; }
40 | #HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
41 | #HTMLReporter .summary { margin-top: 14px; }
42 | #HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
43 | #HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
44 | #HTMLReporter .summary .specSummary.failed a { color: #b03911; }
45 | #HTMLReporter .description + .suite { margin-top: 0; }
46 | #HTMLReporter .suite { margin-top: 14px; }
47 | #HTMLReporter .suite a { color: #333333; }
48 | #HTMLReporter #details .specDetail { margin-bottom: 28px; }
49 | #HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
50 | #HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
51 | #HTMLReporter .resultMessage span.result { display: block; }
52 | #HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
53 |
54 | #TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
55 | #TrivialReporter a:visited, #TrivialReporter a { color: #303; }
56 | #TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
57 | #TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
58 | #TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
59 | #TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
60 | #TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
61 | #TrivialReporter .runner.running { background-color: yellow; }
62 | #TrivialReporter .options { text-align: right; font-size: .8em; }
63 | #TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
64 | #TrivialReporter .suite .suite { margin: 5px; }
65 | #TrivialReporter .suite.passed { background-color: #dfd; }
66 | #TrivialReporter .suite.failed { background-color: #fdd; }
67 | #TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
68 | #TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
69 | #TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
70 | #TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
71 | #TrivialReporter .spec.skipped { background-color: #bbb; }
72 | #TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
73 | #TrivialReporter .passed { background-color: #cfc; display: none; }
74 | #TrivialReporter .failed { background-color: #fbb; }
75 | #TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
76 | #TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
77 | #TrivialReporter .resultMessage .mismatch { color: black; }
78 | #TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
79 | #TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
80 | #TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
81 | #TrivialReporter #jasmine_content { position: fixed; right: 100%; }
82 | #TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
83 |
--------------------------------------------------------------------------------
/Excel/Table.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module Excel/Table
3 | */
4 | define(['underscore', './util'], function (_, util) {
5 | "use strict";
6 | var Table = function (config) {
7 | _.defaults(this, {
8 | name: "",
9 | displayName: "",
10 | dataCellStyle: null,
11 | dataDfxId: null,
12 | headerRowBorderDxfId: null,
13 | headerRowCellStyle: null,
14 | headerRowCount: 1,
15 | headerRowDxfId: null,
16 | insertRow: false,
17 | insertRowShift: false,
18 | ref: null,
19 | tableBorderDxfId: null,
20 | totalsRowBorderDxfId: null,
21 | totalsRowCellStyle: null,
22 | totalsRowCount: 0,
23 | totalsRowDxfId: null,
24 | tableColumns: [],
25 | autoFilter: null,
26 | sortState: null,
27 | styleInfo: {}
28 | });
29 | this.initialize(config);
30 | };
31 | _.extend(Table.prototype, {
32 |
33 | initialize: function (config) {
34 | this.displayName = _.uniqueId("Table");
35 | this.name = this.displayName;
36 | this.id = this.name;
37 | this.tableId = this.id.replace('Table', '');
38 | _.extend(this, config);
39 | },
40 |
41 | setReferenceRange: function (start, end) {
42 | this.ref = [start, end];
43 | },
44 |
45 | setTableColumns: function (columns) {
46 | _.each(columns, function (column) {
47 | this.addTableColumn(column);
48 | }, this);
49 | },
50 |
51 | /**
52 | * Expects an object with the following optional properties:
53 | * name (required)
54 | * dataCellStyle
55 | * dataDxfId
56 | * headerRowCellStyle
57 | * headerRowDxfId
58 | * totalsRowCellStyle
59 | * totalsRowDxfId
60 | * totalsRowFunction
61 | * totalsRowLabel
62 | * columnFormula
63 | * columnFormulaIsArrayType (boolean)
64 | * totalFormula
65 | * totalFormulaIsArrayType (boolean)
66 | */
67 | addTableColumn: function (column) {
68 | if(_.isString(column)) {
69 | column = {
70 | name: column
71 | };
72 | }
73 | if(!column.name) {
74 | throw "Invalid argument for addTableColumn - minimum requirement is a name property";
75 | }
76 | this.tableColumns.push(column);
77 | },
78 |
79 | /**
80 | * Expects an object with the following properties:
81 | * caseSensitive (boolean)
82 | * dataRange
83 | * columnSort (assumes true)
84 | * sortDirection
85 | * sortRange (defaults to dataRange)
86 | */
87 | setSortState: function (state) {
88 | this.sortState = state;
89 | },
90 |
91 | toXML: function () {
92 | var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'table');
93 | var table = doc.documentElement;
94 | table.setAttribute('id', this.tableId);
95 | table.setAttribute('name', this.name);
96 | table.setAttribute('displayName', this.displayName);
97 | var s = this.ref[0];
98 | var e = this.ref[1];
99 | table.setAttribute('ref', util.positionToLetterRef(s[0], s[1]) + ":" + util.positionToLetterRef(e[0], e[1]));
100 |
101 | /** TOTALS **/
102 | table.setAttribute('totalsRowCount', this.totalsRowCount);
103 |
104 | /** HEADER **/
105 | table.setAttribute('headerRowCount', this.headerRowCount);
106 | if(this.headerRowDxfId) {
107 | table.setAttribute('headerRowDxfId', this.headerRowDxfId);
108 | }
109 | if(this.headerRowBorderDxfId) {
110 | table.setAttribute('headerRowBorderDxfId', this.headerRowBorderDxfId);
111 | }
112 |
113 | if(!this.ref) {
114 | throw "Needs at least a reference range";
115 | }
116 | if(!this.autoFilter) {
117 | this.addAutoFilter(this.ref[0], this.ref[1]);
118 | }
119 |
120 | table.appendChild(this.exportAutoFilter(doc));
121 |
122 | table.appendChild(this.exportTableColumns(doc));
123 | table.appendChild(this.exportTableStyleInfo(doc));
124 | return doc;
125 | },
126 |
127 | exportTableColumns: function (doc) {
128 | var tableColumns = doc.createElement('tableColumns');
129 | tableColumns.setAttribute('count', this.tableColumns.length);
130 | var tcs = this.tableColumns;
131 | for(var i = 0, l = tcs.length; i < l; i++) {
132 | var tc = tcs[i];
133 | var tableColumn = doc.createElement('tableColumn');
134 | tableColumn.setAttribute('id', i + 1);
135 | tableColumn.setAttribute('name', tc.name);
136 | tableColumns.appendChild(tableColumn);
137 |
138 | if(tc.totalsRowFunction) {
139 | tableColumn.setAttribute('totalsRowFunction', tc.totalsRowFunction);
140 | }
141 | if(tc.totalsRowLabel) {
142 | tableColumn.setAttribute('totalsRowLabel', tc.totalsRowLabel);
143 | }
144 | }
145 | return tableColumns;
146 | },
147 |
148 | exportAutoFilter: function (doc) {
149 | var autoFilter = doc.createElement('autoFilter');
150 | var s = this.autoFilter[0];
151 | var e = this.autoFilter[1];
152 | autoFilter.setAttribute('ref', util.positionToLetterRef(s[0], s[1]) + ":" + util.positionToLetterRef(e[0], e[1] - this.totalsRowCount));
153 | return autoFilter;
154 | },
155 |
156 | exportTableStyleInfo: function (doc) {
157 | var ts = this.styleInfo;
158 | var tableStyle = doc.createElement('tableStyleInfo');
159 | tableStyle.setAttribute('name', ts.themeStyle);
160 | tableStyle.setAttribute('showFirstColumn', ts.showFirstColumn ? "1" : "0");
161 | tableStyle.setAttribute('showLastColumn', ts.showLastColumn ? "1" : "0");
162 | tableStyle.setAttribute('showColumnStripes', ts.showColumnStripes ? "1" : "0");
163 | tableStyle.setAttribute('showRowStripes', ts.showRowStripes ? "1" : "0");
164 | return tableStyle;
165 | },
166 |
167 | addAutoFilter: function (startRef, endRef) {
168 | this.autoFilter = [startRef, endRef];
169 | }
170 | });
171 | return Table;
172 | });
173 |
--------------------------------------------------------------------------------
/demo/downloadify/src/downloadify.js:
--------------------------------------------------------------------------------
1 | /*
2 | Downloadify: Client Side File Creation
3 | JavaScript + Flash Library
4 |
5 | Version: 0.2
6 |
7 | Copyright (c) 2009 Douglas C. Neiner
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
26 | */
27 |
28 | (function(){
29 | Downloadify = window.Downloadify = {
30 | queue: {},
31 | uid: new Date().getTime(),
32 | getTextForSave: function(queue){
33 | var obj = Downloadify.queue[queue];
34 | if(obj) return obj.getData();
35 | return "";
36 | },
37 | getFileNameForSave: function(queue){
38 | var obj = Downloadify.queue[queue];
39 | if(obj) return obj.getFilename();
40 | return "";
41 | },
42 | getDataTypeForSave: function(queue){
43 | var obj = Downloadify.queue[queue];
44 | if(obj) return obj.getDataType();
45 | return "";
46 | },
47 | saveComplete: function(queue){
48 | var obj = Downloadify.queue[queue];
49 | if(obj) obj.complete();
50 | return true;
51 | },
52 | saveCancel: function(queue){
53 | var obj = Downloadify.queue[queue];
54 | if(obj) obj.cancel();
55 | return true;
56 | },
57 | saveError: function(queue){
58 | var obj = Downloadify.queue[queue];
59 | if(obj) obj.error();
60 | return true;
61 | },
62 | addToQueue: function(container){
63 | Downloadify.queue[container.queue_name] = container;
64 | },
65 | // Concept adapted from: http://tinyurl.com/yzsyfto
66 | // SWF object runs off of ID's, so this is the good way to get a unique ID
67 | getUID: function(el){
68 | if(el.id == "") el.id = 'downloadify_' + Downloadify.uid++;
69 | return el.id;
70 | }
71 | };
72 |
73 | Downloadify.create = function( idOrDOM, options ){
74 | var el = (typeof(idOrDOM) == "string" ? document.getElementById(idOrDOM) : idOrDOM );
75 | return new Downloadify.Container(el, options);
76 | };
77 |
78 | Downloadify.Container = function(el, options){
79 | var base = this;
80 |
81 | base.el = el;
82 | base.enabled = true;
83 | base.dataCallback = null;
84 | base.filenameCallback = null;
85 | base.data = null;
86 | base.filename = null;
87 |
88 | var init = function(){
89 | base.options = options;
90 |
91 | if( !base.options.append ) base.el.innerHTML = "";
92 |
93 | base.flashContainer = document.createElement('span');
94 | base.el.appendChild(base.flashContainer);
95 |
96 | base.queue_name = Downloadify.getUID( base.flashContainer );
97 |
98 | if( typeof(base.options.filename) === "function" )
99 | base.filenameCallback = base.options.filename;
100 | else if (base.options.filename)
101 | base.filename = base.options.filename;
102 |
103 | if( typeof(base.options.data) === "function" )
104 | base.dataCallback = base.options.data;
105 | else if (base.options.data)
106 | base.data = base.options.data;
107 |
108 |
109 | var flashVars = {
110 | queue_name: base.queue_name,
111 | width: base.options.width,
112 | height: base.options.height
113 | };
114 |
115 | var params = {
116 | allowScriptAccess: 'always'
117 | };
118 |
119 | var attributes = {
120 | id: base.flashContainer.id,
121 | name: base.flashContainer.id
122 | };
123 |
124 | if(base.options.enabled === false) base.enabled = false;
125 |
126 | if(base.options.transparent === true) params.wmode = "transparent";
127 |
128 | if(base.options.downloadImage) flashVars.downloadImage = base.options.downloadImage;
129 |
130 | swfobject.embedSWF(base.options.swf, base.flashContainer.id, base.options.width, base.options.height, "10", null, flashVars, params, attributes );
131 |
132 | Downloadify.addToQueue( base );
133 | };
134 |
135 | base.enable = function(){
136 | var swf = document.getElementById(base.flashContainer.id);
137 | swf.setEnabled(true);
138 | base.enabled = true;
139 | };
140 |
141 | base.disable = function(){
142 | var swf = document.getElementById(base.flashContainer.id);
143 | swf.setEnabled(false);
144 | base.enabled = false;
145 | };
146 |
147 | base.getData = function(){
148 | if( !base.enabled ) return "";
149 | if( base.dataCallback ) return base.dataCallback();
150 | else if (base.data) return base.data;
151 | else return "";
152 | };
153 |
154 | base.getFilename = function(){
155 | if( base.filenameCallback ) return base.filenameCallback();
156 | else if (base.filename) return base.filename;
157 | else return "";
158 | };
159 |
160 | base.getDataType = function(){
161 | if (base.options.dataType) return base.options.dataType;
162 | return "string";
163 | };
164 |
165 | base.complete = function(){
166 | if( typeof(base.options.onComplete) === "function" ) base.options.onComplete();
167 | };
168 |
169 | base.cancel = function(){
170 | if( typeof(base.options.onCancel) === "function" ) base.options.onCancel();
171 | };
172 |
173 | base.error = function(){
174 | if( typeof(base.options.onError) === "function" ) base.options.onError();
175 | };
176 |
177 | init();
178 | };
179 |
180 | Downloadify.defaultOptions = {
181 | swf: 'media/downloadify.swf',
182 | downloadImage: 'images/download.png',
183 | width: 100,
184 | height: 30,
185 | transparent: true,
186 | append: false,
187 | dataType: "string"
188 | };
189 | })();
190 |
191 | // Support for jQuery
192 | if(typeof(jQuery) != "undefined"){
193 | (function($){
194 | $.fn.downloadify = function(options){
195 | return this.each(function(){
196 | options = $.extend({}, Downloadify.defaultOptions, options);
197 | var dl = Downloadify.create( this, options);
198 | $(this).data('Downloadify', dl);
199 | });
200 | };
201 | })(jQuery);
202 | };
203 |
204 | /* mootools helper */
205 | if(typeof(MooTools) != 'undefined'){
206 | Element.implement({
207 | downloadify: function(options) {
208 | options = $merge(Downloadify.defaultOptions,options);
209 | return this.store('Downloadify',Downloadify.create(this,options));
210 | }
211 | });
212 | };
213 |
214 |
--------------------------------------------------------------------------------
/demo/downloadify/README.textile:
--------------------------------------------------------------------------------
1 | h2. Downloadify: Client Side File Creation
2 |
3 | *_Important! The swf has been compiled for online use only. Testing from the file path (i.e. file:// ) will not work as it will violate the security sandbox._*
4 |
5 | h3. Overview
6 |
7 | This library is a tiny JavaScript + Flash library that allows you to generate files on the fly, in the browser, without server interaction. Web applications that allow you to generate vCards, color palettes, custom code, etc would benefit from using this library. In addition to increasing speed (no round trip to the server) this solution can reduce the database and server load of existing web applications. _This is not a library to 'force download' a file from a server. It does not interact with a server at all._
8 |
9 | h3. Demo
10 |
11 | A "very simple demo is available":http://pixelgraphics.us/downloadify/test.html that lets you supply your own content and filename and test out saving, canceling, and the error functionality when the file is blank.
12 |
13 | For a real world usage, see "Starter for jQuery":http://starter.pixelgraphics.us . To quickly demo the usage, just click "Load Example Data" then click Download. After the initial page load, no further contact is made with the server. Everything happens on the client side.
14 |
15 | h3. Download
16 |
17 | Please download from the "Downloads":http://github.com/dcneiner/Downloadify/downloads section of this project.
18 |
19 | h3. Support
20 |
21 | For support, please use the "Issues":http://github.com/dcneiner/Downloadify/issues section of this project. You can also try to hit me up on "Twitter at @dougneiner":http://twitter.com/dougneiner but I might just ask you to file an issue. :)
22 |
23 | h3. Dependencies
24 |
25 | _The end user must have Flash 10 or higher installed for this plugin to work. As of September 2009, it was at a 93% saturation, so most users should already have it installed._
26 |
27 | Downloadify is only dependent on "SWFObject 2.0":http://code.google.com/p/swfobject/ which is included with the download. It is compatible with any JavaScript framework but has a helper for both jQuery and MooTools. Neither helper will be activatd if Downloadify is inserted prior to including the framework library.
28 |
29 | h3. Usage
30 |
31 | *Any JavaScript framework*:
32 |
33 | Downloadify.create( id_or_DOM_element, options );
34 |
35 | *jQuery*:
36 |
37 | $("#element").downloadify( options );
38 |
39 | *MooTools:*
40 |
41 | $("elementid").downloadify( options );
42 |
43 | h3. Options
44 |
45 | Unless you are using the jQuery plugin included with Downloadify, you must supply all required options with your call to the Downloadify.create function.
46 |
47 | *Defaults and Required Options*
48 |
49 | * swf : 'media/downloadify.swf' *Required* _Path to the SWF File. Can be relative from the page, or an absolute path._
50 | * downloadImage : 'images/download.png' *Required* _Path to the Button Image. Can be relative from the page or an absolute path._
51 | * width : 175 *Required* _Width of the button (and the flash movie)_
52 | * height : 55 *Required* _Height of the button. This will be 1/4 the height of the image._
53 | * filename : *Required* _Can be a String or a function callback. If a function, the return value of the function will be used as the filename._
54 | * data : *Required* _Can be a normal String, base64 encoded String, or a function callback. If a function, the return value of the function will be used as the file data._
55 | * dataType : 'string' _Must be a String with the value string or base64 . Data paired with the dataType of base64 will be decoded into a ByteArray prior to saving._
56 | * transparent : false _Set this to true to use wmode=transparent on the flash movie._
57 | * append : false _By default the contents of the targeted DOM element are removed. Set this to true to keep the contents and append the button._
58 |
59 | *Event Callbacks*
60 |
61 | No data is passed into these functions, they are simply called.
62 |
63 | * onError : _Called when the Download button is clicked but your data callback returns "" ._
64 | * onCancel : _Called when the Download button is clicked but the user then cancels without saving._
65 | * onComplete : _Called when the Download button is clicked and the file is saved to the user's computer._
66 |
67 | h3. Setting Up the Image
68 |
69 | Downloadify supports (i.e. requires) three button states with limited support for a fourth. The states are:
70 |
71 | * *Normal*
72 | * *Over* ( When the mouse hovers over the button )
73 | * *Down* ( When the button is pressed )
74 | * *Disabled* ( Limited support, when .disable() is called on the Downloadify.Container object )
75 |
76 | In trying to keep this plugin as simple as possible, all four states are always assumed to be present. You should prepare your button image as a single image the width you want your button, and four times the height of the button. All four states should then live in that one image in the same order as the previous list from top to bottom.
77 |
78 | h3. Potential Issues
79 |
80 | When working with different button images, you may find Flash has cached your image. This is the desired behavior on a live site, but not during development. To get around this, simply supply a ?rev=1 or ?rev=2 etc on the end of your downloadImage url.
81 |
82 | h3. Compiling Notes
83 |
84 | I develop locally using Xcode and the Flex 4 SDK Beta 2. Please do not submit request on how to setup a local testing environment. If you are interested in my Xcode project files, send me a message.
85 |
86 | h3. Developers
87 |
88 | *Core Developer:* "Doug Neiner":http://dougneiner.com
89 |
90 | *Contributors:*
91 |
92 | * "David Walsh":http://davidwalsh.name -- Contributed the MooTools helper
93 |
94 | h3. Change Log
95 |
96 | * *Version 0.2*:
97 | ** Added support for base64 via the "as3base64 Library":http://github.com/spjwebster/as3base64
98 | ** Added dataType option
99 | ** Added MooTools helper (Thanks David!)
100 | ** Upgraded SWFObject to v2.2
101 | * *Original Release:* Version 0.1
102 |
103 | h3. License Information: MIT
104 |
105 | as3base64: "Copyright (c) 2006 Steve Webster":http://github.com/spjwebster/as3base64
106 |
107 | All Downloadify Code: Copyright (c) 2009 Douglas C. Neiner
108 |
109 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
110 |
111 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
112 |
113 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/demo/excel-issues-test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | merge cells issue
16 |
17 | worksheet name length issue
18 |
19 |
20 |
159 |
160 |
161 |
162 |
--------------------------------------------------------------------------------
/demo/downloadify/js/swfobject.js:
--------------------------------------------------------------------------------
1 | /* SWFObject v2.2
2 | is released under the MIT License
3 | */
4 | var swfobject=function(){var D="undefined",r="object",S="Shockwave Flash",W="ShockwaveFlash.ShockwaveFlash",q="application/x-shockwave-flash",R="SWFObjectExprInst",x="onreadystatechange",O=window,j=document,t=navigator,T=false,U=[h],o=[],N=[],I=[],l,Q,E,B,J=false,a=false,n,G,m=true,M=function(){var aa=typeof j.getElementById!=D&&typeof j.getElementsByTagName!=D&&typeof j.createElement!=D,ah=t.userAgent.toLowerCase(),Y=t.platform.toLowerCase(),ae=Y?/win/.test(Y):/win/.test(ah),ac=Y?/mac/.test(Y):/mac/.test(ah),af=/webkit/.test(ah)?parseFloat(ah.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,X=!+"\v1",ag=[0,0,0],ab=null;if(typeof t.plugins!=D&&typeof t.plugins[S]==r){ab=t.plugins[S].description;if(ab&&!(typeof t.mimeTypes!=D&&t.mimeTypes[q]&&!t.mimeTypes[q].enabledPlugin)){T=true;X=false;ab=ab.replace(/^.*\s+(\S+\s+\S+$)/,"$1");ag[0]=parseInt(ab.replace(/^(.*)\..*$/,"$1"),10);ag[1]=parseInt(ab.replace(/^.*\.(.*)\s.*$/,"$1"),10);ag[2]=/[a-zA-Z]/.test(ab)?parseInt(ab.replace(/^.*[a-zA-Z]+(.*)$/,"$1"),10):0}}else{if(typeof O.ActiveXObject!=D){try{var ad=new ActiveXObject(W);if(ad){ab=ad.GetVariable("$version");if(ab){X=true;ab=ab.split(" ")[1].split(",");ag=[parseInt(ab[0],10),parseInt(ab[1],10),parseInt(ab[2],10)]}}}catch(Z){}}}return{w3:aa,pv:ag,wk:af,ie:X,win:ae,mac:ac}}(),k=function(){if(!M.w3){return}if((typeof j.readyState!=D&&j.readyState=="complete")||(typeof j.readyState==D&&(j.getElementsByTagName("body")[0]||j.body))){f()}if(!J){if(typeof j.addEventListener!=D){j.addEventListener("DOMContentLoaded",f,false)}if(M.ie&&M.win){j.attachEvent(x,function(){if(j.readyState=="complete"){j.detachEvent(x,arguments.callee);f()}});if(O==top){(function(){if(J){return}try{j.documentElement.doScroll("left")}catch(X){setTimeout(arguments.callee,0);return}f()})()}}if(M.wk){(function(){if(J){return}if(!/loaded|complete/.test(j.readyState)){setTimeout(arguments.callee,0);return}f()})()}s(f)}}();function f(){if(J){return}try{var Z=j.getElementsByTagName("body")[0].appendChild(C("span"));Z.parentNode.removeChild(Z)}catch(aa){return}J=true;var X=U.length;for(var Y=0;Y0){for(var af=0;af0){var ae=c(Y);if(ae){if(F(o[af].swfVersion)&&!(M.wk&&M.wk<312)){w(Y,true);if(ab){aa.success=true;aa.ref=z(Y);ab(aa)}}else{if(o[af].expressInstall&&A()){var ai={};ai.data=o[af].expressInstall;ai.width=ae.getAttribute("width")||"0";ai.height=ae.getAttribute("height")||"0";if(ae.getAttribute("class")){ai.styleclass=ae.getAttribute("class")}if(ae.getAttribute("align")){ai.align=ae.getAttribute("align")}var ah={};var X=ae.getElementsByTagName("param");var ac=X.length;for(var ad=0;ad '}}aa.outerHTML='"+af+" ";N[N.length]=ai.id;X=c(ai.id)}else{var Z=C(r);Z.setAttribute("type",q);for(var ac in ai){if(ai[ac]!=Object.prototype[ac]){if(ac.toLowerCase()=="styleclass"){Z.setAttribute("class",ai[ac])}else{if(ac.toLowerCase()!="classid"){Z.setAttribute(ac,ai[ac])}}}}for(var ab in ag){if(ag[ab]!=Object.prototype[ab]&&ab.toLowerCase()!="movie"){e(Z,ab,ag[ab])}}aa.parentNode.replaceChild(Z,aa);X=Z}}return X}function e(Z,X,Y){var aa=C("param");aa.setAttribute("name",X);aa.setAttribute("value",Y);Z.appendChild(aa)}function y(Y){var X=c(Y);if(X&&X.nodeName=="OBJECT"){if(M.ie&&M.win){X.style.display="none";(function(){if(X.readyState==4){b(Y)}else{setTimeout(arguments.callee,10)}})()}else{X.parentNode.removeChild(X)}}}function b(Z){var Y=c(Z);if(Y){for(var X in Y){if(typeof Y[X]=="function"){Y[X]=null}}Y.parentNode.removeChild(Y)}}function c(Z){var X=null;try{X=j.getElementById(Z)}catch(Y){}return X}function C(X){return j.createElement(X)}function i(Z,X,Y){Z.attachEvent(X,Y);I[I.length]=[Z,X,Y]}function F(Z){var Y=M.pv,X=Z.split(".");X[0]=parseInt(X[0],10);X[1]=parseInt(X[1],10)||0;X[2]=parseInt(X[2],10)||0;return(Y[0]>X[0]||(Y[0]==X[0]&&Y[1]>X[1])||(Y[0]==X[0]&&Y[1]==X[1]&&Y[2]>=X[2]))?true:false}function v(ac,Y,ad,ab){if(M.ie&&M.mac){return}var aa=j.getElementsByTagName("head")[0];if(!aa){return}var X=(ad&&typeof ad=="string")?ad:"screen";if(ab){n=null;G=null}if(!n||G!=X){var Z=C("style");Z.setAttribute("type","text/css");Z.setAttribute("media",X);n=aa.appendChild(Z);if(M.ie&&M.win&&typeof j.styleSheets!=D&&j.styleSheets.length>0){n=j.styleSheets[j.styleSheets.length-1]}G=X}if(M.ie&&M.win){if(n&&typeof n.addRule==r){n.addRule(ac,Y)}}else{if(n&&typeof j.createTextNode!=D){n.appendChild(j.createTextNode(ac+" {"+Y+"}"))}}}function w(Z,X){if(!m){return}var Y=X?"visible":"hidden";if(J&&c(Z)){c(Z).style.visibility=Y}else{v("#"+Z,"visibility:"+Y)}}function L(Y){var Z=/[\\\"<>\.;]/;var X=Z.exec(Y)!=null;return X&&typeof encodeURIComponent!=D?encodeURIComponent(Y):Y}var d=function(){if(M.ie&&M.win){window.attachEvent("onunload",function(){var ac=I.length;for(var ab=0;ab/im,
16 | bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im,
17 | hasLocation = typeof location !== 'undefined' && location.href,
18 | defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''),
19 | defaultHostName = hasLocation && location.hostname,
20 | defaultPort = hasLocation && (location.port || undefined),
21 | buildMap = [],
22 | masterConfig = (module.config && module.config()) || {},
23 | text, fs;
24 |
25 | text = {
26 | version: '2.0.1',
27 |
28 | strip: function (content) {
29 | //Strips declarations so that external SVG and XML
30 | //documents can be added to a document without worry. Also, if the string
31 | //is an HTML document, only the part inside the body tag is returned.
32 | if (content) {
33 | content = content.replace(xmlRegExp, "");
34 | var matches = content.match(bodyRegExp);
35 | if (matches) {
36 | content = matches[1];
37 | }
38 | } else {
39 | content = "";
40 | }
41 | return content;
42 | },
43 |
44 | jsEscape: function (content) {
45 | return content.replace(/(['\\])/g, '\\$1')
46 | .replace(/[\f]/g, "\\f")
47 | .replace(/[\b]/g, "\\b")
48 | .replace(/[\n]/g, "\\n")
49 | .replace(/[\t]/g, "\\t")
50 | .replace(/[\r]/g, "\\r")
51 | .replace(/[\u2028]/g, "\\u2028")
52 | .replace(/[\u2029]/g, "\\u2029");
53 | },
54 |
55 | createXhr: masterConfig.createXhr || function () {
56 | //Would love to dump the ActiveX crap in here. Need IE 6 to die first.
57 | var xhr, i, progId;
58 | if (typeof XMLHttpRequest !== "undefined") {
59 | return new XMLHttpRequest();
60 | } else if (typeof ActiveXObject !== "undefined") {
61 | for (i = 0; i < 3; i += 1) {
62 | progId = progIds[i];
63 | try {
64 | xhr = new ActiveXObject(progId);
65 | } catch (e) {}
66 |
67 | if (xhr) {
68 | progIds = [progId]; // so faster next time
69 | break;
70 | }
71 | }
72 | }
73 |
74 | return xhr;
75 | },
76 |
77 | /**
78 | * Parses a resource name into its component parts. Resource names
79 | * look like: module/name.ext!strip, where the !strip part is
80 | * optional.
81 | * @param {String} name the resource name
82 | * @returns {Object} with properties "moduleName", "ext" and "strip"
83 | * where strip is a boolean.
84 | */
85 | parseName: function (name) {
86 | var strip = false, index = name.indexOf("."),
87 | modName = name.substring(0, index),
88 | ext = name.substring(index + 1, name.length);
89 |
90 | index = ext.indexOf("!");
91 | if (index !== -1) {
92 | //Pull off the strip arg.
93 | strip = ext.substring(index + 1, ext.length);
94 | strip = strip === "strip";
95 | ext = ext.substring(0, index);
96 | }
97 |
98 | return {
99 | moduleName: modName,
100 | ext: ext,
101 | strip: strip
102 | };
103 | },
104 |
105 | xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/,
106 |
107 | /**
108 | * Is an URL on another domain. Only works for browser use, returns
109 | * false in non-browser environments. Only used to know if an
110 | * optimized .js version of a text resource should be loaded
111 | * instead.
112 | * @param {String} url
113 | * @returns Boolean
114 | */
115 | useXhr: function (url, protocol, hostname, port) {
116 | var match = text.xdRegExp.exec(url),
117 | uProtocol, uHostName, uPort;
118 | if (!match) {
119 | return true;
120 | }
121 | uProtocol = match[2];
122 | uHostName = match[3];
123 |
124 | uHostName = uHostName.split(':');
125 | uPort = uHostName[1];
126 | uHostName = uHostName[0];
127 |
128 | return (!uProtocol || uProtocol === protocol) &&
129 | (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) &&
130 | ((!uPort && !uHostName) || uPort === port);
131 | },
132 |
133 | finishLoad: function (name, strip, content, onLoad) {
134 | content = strip ? text.strip(content) : content;
135 | if (masterConfig.isBuild) {
136 | buildMap[name] = content;
137 | }
138 | onLoad(content);
139 | },
140 |
141 | load: function (name, req, onLoad, config) {
142 | //Name has format: some.module.filext!strip
143 | //The strip part is optional.
144 | //if strip is present, then that means only get the string contents
145 | //inside a body tag in an HTML string. For XML/SVG content it means
146 | //removing the declarations so the content can be inserted
147 | //into the current doc without problems.
148 |
149 | // Do not bother with the work if a build and text will
150 | // not be inlined.
151 | if (config.isBuild && !config.inlineText) {
152 | onLoad();
153 | return;
154 | }
155 |
156 | masterConfig.isBuild = config.isBuild;
157 |
158 | var parsed = text.parseName(name),
159 | nonStripName = parsed.moduleName + '.' + parsed.ext,
160 | url = req.toUrl(nonStripName),
161 | useXhr = (masterConfig.useXhr) ||
162 | text.useXhr;
163 |
164 | //Load the text. Use XHR if possible and in a browser.
165 | if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) {
166 | text.get(url, function (content) {
167 | text.finishLoad(name, parsed.strip, content, onLoad);
168 | }, function (err) {
169 | if (onLoad.error) {
170 | onLoad.error(err);
171 | }
172 | });
173 | } else {
174 | //Need to fetch the resource across domains. Assume
175 | //the resource has been optimized into a JS module. Fetch
176 | //by the module name + extension, but do not include the
177 | //!strip part to avoid file system issues.
178 | req([nonStripName], function (content) {
179 | text.finishLoad(parsed.moduleName + '.' + parsed.ext,
180 | parsed.strip, content, onLoad);
181 | });
182 | }
183 | },
184 |
185 | write: function (pluginName, moduleName, write, config) {
186 | if (buildMap.hasOwnProperty(moduleName)) {
187 | var content = text.jsEscape(buildMap[moduleName]);
188 | write.asModule(pluginName + "!" + moduleName,
189 | "define(function () { return '" +
190 | content +
191 | "';});\n");
192 | }
193 | },
194 |
195 | writeFile: function (pluginName, moduleName, req, write, config) {
196 | var parsed = text.parseName(moduleName),
197 | nonStripName = parsed.moduleName + '.' + parsed.ext,
198 | //Use a '.js' file name so that it indicates it is a
199 | //script that can be loaded across domains.
200 | fileName = req.toUrl(parsed.moduleName + '.' +
201 | parsed.ext) + '.js';
202 |
203 | //Leverage own load() method to load plugin value, but only
204 | //write out values that do not have the strip argument,
205 | //to avoid any potential issues with ! in file names.
206 | text.load(nonStripName, req, function (value) {
207 | //Use own write() method to construct full module value.
208 | //But need to create shell that translates writeFile's
209 | //write() to the right interface.
210 | var textWrite = function (contents) {
211 | return write(fileName, contents);
212 | };
213 | textWrite.asModule = function (moduleName, contents) {
214 | return write.asModule(moduleName, fileName, contents);
215 | };
216 |
217 | text.write(pluginName, nonStripName, textWrite, config);
218 | }, config);
219 | }
220 | };
221 |
222 | if (typeof process !== "undefined" &&
223 | process.versions &&
224 | !!process.versions.node) {
225 | //Using special require.nodeRequire, something added by r.js.
226 | fs = require.nodeRequire('fs');
227 |
228 | text.get = function (url, callback) {
229 | var file = fs.readFileSync(url, 'utf8');
230 | //Remove BOM (Byte Mark Order) from utf8 files if it is there.
231 | if (file.indexOf('\uFEFF') === 0) {
232 | file = file.substring(1);
233 | }
234 | callback(file);
235 | };
236 | } else if (text.createXhr()) {
237 | text.get = function (url, callback, errback) {
238 | var xhr = text.createXhr();
239 | xhr.open('GET', url, true);
240 |
241 | //Allow overrides specified in config
242 | if (masterConfig.onXhr) {
243 | masterConfig.onXhr(xhr, url);
244 | }
245 |
246 | xhr.onreadystatechange = function (evt) {
247 | var status, err;
248 | //Do not explicitly handle errors, those should be
249 | //visible via console output in the browser.
250 | if (xhr.readyState === 4) {
251 | status = xhr.status;
252 | if (status > 399 && status < 600) {
253 | //An http 4xx or 5xx error. Signal an error.
254 | err = new Error(url + ' HTTP status: ' + status);
255 | err.xhr = xhr;
256 | errback(err);
257 | } else {
258 | callback(xhr.responseText);
259 | }
260 | }
261 | };
262 | xhr.send(null);
263 | };
264 | } else if (typeof Packages !== 'undefined') {
265 | //Why Java, why is this so awkward?
266 | text.get = function (url, callback) {
267 | var encoding = "utf-8",
268 | file = new java.io.File(url),
269 | lineSeparator = java.lang.System.getProperty("line.separator"),
270 | input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)),
271 | stringBuffer, line,
272 | content = '';
273 | try {
274 | stringBuffer = new java.lang.StringBuffer();
275 | line = input.readLine();
276 |
277 | // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324
278 | // http://www.unicode.org/faq/utf_bom.html
279 |
280 | // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK:
281 | // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058
282 | if (line && line.length() && line.charAt(0) === 0xfeff) {
283 | // Eat the BOM, since we've already found the encoding on this file,
284 | // and we plan to concatenating this buffer with others; the BOM should
285 | // only appear at the top of a file.
286 | line = line.substring(1);
287 | }
288 |
289 | stringBuffer.append(line);
290 |
291 | while ((line = input.readLine()) !== null) {
292 | stringBuffer.append(lineSeparator);
293 | stringBuffer.append(line);
294 | }
295 | //Make sure we return a JavaScript string and not a Java string.
296 | content = String(stringBuffer.toString()); //String
297 | } finally {
298 | input.close();
299 | }
300 | callback(content);
301 | };
302 | }
303 |
304 | return text;
305 | });
306 |
--------------------------------------------------------------------------------
/Excel/Workbook.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @module Excel/Workbook
3 | */
4 | define([
5 | 'require',
6 | 'underscore',
7 | './util',
8 | './StyleSheet',
9 | './Worksheet',
10 | './SharedStrings',
11 | './RelationshipManager',
12 | './Paths',
13 | './XMLDOM'
14 | ],
15 | function (require, _, util, StyleSheet, Worksheet, SharedStrings, RelationshipManager, Paths, XMLDOM) {
16 | "use strict";
17 | var Workbook = function (config) {
18 | this.worksheets = [];
19 | this.tables = [];
20 | this.drawings = [];
21 | this.media = {};
22 | this.initialize(config);
23 | };
24 | _.extend(Workbook.prototype, {
25 |
26 | initialize: function () {
27 | this.id = _.uniqueId('Workbook');
28 | this.styleSheet = new StyleSheet();
29 | this.sharedStrings = new SharedStrings();
30 | this.relations = new RelationshipManager();
31 | this.relations.addRelation(this.styleSheet, 'stylesheet');
32 | this.relations.addRelation(this.sharedStrings, 'sharedStrings');
33 | },
34 |
35 | createWorksheet: function (config) {
36 | config = config || {};
37 | _.defaults(config, {
38 | name: 'Sheet '.concat(this.worksheets.length + 1)
39 | });
40 | return new Worksheet(config);
41 | },
42 |
43 | getStyleSheet: function () {
44 | return this.styleSheet;
45 | },
46 |
47 | addTable: function (table) {
48 | this.tables.push(table);
49 | },
50 |
51 | addDrawings: function (drawings) {
52 | this.drawings.push(drawings);
53 | },
54 |
55 | addMedia: function (type, fileName, fileData, contentType) {
56 | var fileNamePieces = fileName.split('.');
57 | var extension = fileNamePieces[fileNamePieces.length - 1];
58 | if(!contentType) {
59 | switch(extension.toLowerCase()) {
60 | case 'jpeg':
61 | case 'jpg':
62 | contentType = "image/jpeg";
63 | break;
64 | case 'png':
65 | contentType = "image/png";
66 | break;
67 | case 'gif':
68 | contentType = "image/gif";
69 | break;
70 | default:
71 | contentType = null;
72 | break;
73 | }
74 | }
75 | if(!this.media[fileName]) {
76 | this.media[fileName] = {
77 | id: fileName,
78 | data: fileData,
79 | fileName: fileName,
80 | contentType: contentType,
81 | extension: extension
82 | };
83 | }
84 | return this.media[fileName];
85 | },
86 |
87 | addWorksheet: function (worksheet) {
88 | this.relations.addRelation(worksheet, 'worksheet');
89 | worksheet.setSharedStringCollection(this.sharedStrings);
90 | this.worksheets.push(worksheet);
91 | },
92 |
93 | createContentTypes: function () {
94 | var doc = util.createXmlDoc(util.schemas.contentTypes, 'Types');
95 | var types = doc.documentElement;
96 | var i, l;
97 |
98 | types.appendChild(util.createElement(doc, 'Default', [
99 | ['Extension', "rels"],
100 | ['ContentType', "application/vnd.openxmlformats-package.relationships+xml"]
101 | ]));
102 | types.appendChild(util.createElement(doc, 'Default', [
103 | ['Extension', "xml"],
104 | ['ContentType', "application/xml"]
105 | ]));
106 |
107 | var extensions = {};
108 | for(var filename in this.media) {
109 | if(this.media.hasOwnProperty(filename)) {
110 | extensions[this.media[filename].extension] = this.media[filename].contentType;
111 | }
112 | }
113 | for(var extension in extensions) {
114 | if(extensions.hasOwnProperty(extension)) {
115 | types.appendChild(util.createElement(doc, 'Default', [
116 | ['Extension', extension],
117 | ['ContentType', extensions[extension]]
118 | ]));
119 | }
120 | }
121 |
122 | types.appendChild(util.createElement(doc, 'Override', [
123 | ['PartName', "/xl/workbook.xml"],
124 | ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"]
125 | ]));
126 | types.appendChild(util.createElement(doc, 'Override', [
127 | ['PartName', "/xl/sharedStrings.xml"],
128 | ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"]
129 | ]));
130 | types.appendChild(util.createElement(doc, 'Override', [
131 | ['PartName', "/xl/styles.xml"],
132 | ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"]
133 | ]));
134 |
135 | for(i = 0, l = this.worksheets.length; i < l; i++) {
136 | types.appendChild(util.createElement(doc, 'Override', [
137 | ['PartName', "/xl/worksheets/sheet" + (i + 1) + ".xml"],
138 | ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"]
139 | ]));
140 | }
141 | for(i = 0, l = this.tables.length; i < l; i++) {
142 | types.appendChild(util.createElement(doc, 'Override', [
143 | ['PartName', "/xl/tables/table" + (i + 1) + ".xml"],
144 | ['ContentType', "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"]
145 | ]));
146 | }
147 |
148 | for(i = 0, l = this.drawings.length; i < l; i++) {
149 | types.appendChild(util.createElement(doc, 'Override', [
150 | ['PartName', '/xl/drawings/drawing' + (i + 1) + '.xml'],
151 | ['ContentType', 'application/vnd.openxmlformats-officedocument.drawing+xml']
152 | ]));
153 | }
154 |
155 | return doc;
156 | },
157 |
158 | toXML: function () {
159 | var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'workbook');
160 | var wb = doc.documentElement;
161 | wb.setAttribute('xmlns:r', util.schemas.relationships);
162 |
163 | var maxWorksheetNameLength = 31;
164 | var sheets = util.createElement(doc, 'sheets');
165 | for(var i = 0, l = this.worksheets.length; i < l; i++) {
166 | var sheet = doc.createElement('sheet');
167 | // Microsoft Excel (2007, 2013) do not allow worksheet names longer than 31 characters
168 | // if the worksheet name is longer, Excel displays an "Excel found unreadable content..." popup when opening the file
169 | if(console != null && this.worksheets[i].name.length > maxWorksheetNameLength) {
170 | console.log('Microsoft Excel requires work sheet names to be less than ' + (maxWorksheetNameLength+1) +
171 | ' characters long, work sheet name "' + this.worksheets[i].name +
172 | '" is ' + this.worksheets[i].name.length + ' characters long');
173 | }
174 | sheet.setAttribute('name', this.worksheets[i].name);
175 | sheet.setAttribute('sheetId', i + 1);
176 | sheet.setAttribute('r:id', this.relations.getRelationshipId(this.worksheets[i]));
177 | sheets.appendChild(sheet);
178 | }
179 | wb.appendChild(sheets);
180 | return doc;
181 | },
182 |
183 | createWorkbookRelationship: function () {
184 | var doc = util.createXmlDoc(util.schemas.relationshipPackage, 'Relationships');
185 | var relationships = doc.documentElement;
186 | relationships.appendChild(util.createElement(doc, 'Relationship', [
187 | ['Id', 'rId1'],
188 | ['Type', util.schemas.officeDocument],
189 | ['Target', 'xl/workbook.xml']
190 | ]));
191 | return doc;
192 | },
193 |
194 | _generateCorePaths: function (files) {
195 | var i, l;
196 | Paths[this.styleSheet.id] = 'styles.xml';
197 | Paths[this.sharedStrings.id] = 'sharedStrings.xml';
198 | Paths[this.id] = '/xl/workbook.xml';
199 |
200 | for(i = 0, l = this.tables.length; i < l; i++) {
201 | files['/xl/tables/table' + (i + 1) + '.xml'] = this.tables[i].toXML();
202 | Paths[this.tables[i].id] = '/xl/tables/table' + (i + 1) + '.xml';
203 | }
204 |
205 | for(var fileName in this.media) {
206 | if(this.media.hasOwnProperty(fileName)) {
207 | var media = this.media[fileName];
208 | files['/xl/media/' + fileName] = media.data;
209 | Paths[fileName] = '/xl/media/' + fileName;
210 | }
211 | }
212 |
213 | for(i = 0, l = this.drawings.length; i < l; i++) {
214 | files['/xl/drawings/drawing' + (i + 1) + '.xml'] = this.drawings[i].toXML();
215 | Paths[this.drawings[i].id] = '/xl/drawings/drawing' + (i + 1) + '.xml';
216 | files['/xl/drawings/_rels/drawing' + (i + 1) + '.xml.rels'] = this.drawings[i].relations.toXML();
217 | }
218 |
219 |
220 | },
221 |
222 | _prepareFilesForPackaging: function (files) {
223 |
224 | _.extend(files, {
225 | '/[Content_Types].xml': this.createContentTypes(),
226 | '/_rels/.rels': this.createWorkbookRelationship(),
227 | '/xl/styles.xml': this.styleSheet.toXML(),
228 | '/xl/workbook.xml': this.toXML(),
229 | '/xl/sharedStrings.xml': this.sharedStrings.toXML(),
230 | '/xl/_rels/workbook.xml.rels': this.relations.toXML()
231 | });
232 |
233 | _.each(files, function (value, key) {
234 | if(key.indexOf('.xml') !== -1 || key.indexOf('.rels') !== -1) {
235 | if (value instanceof XMLDOM){
236 | files[key] = value.toString();
237 | } else {
238 | files[key] = value.xml || new window.XMLSerializer().serializeToString(value);
239 | }
240 | var content = files[key].replace(/xmlns=""/g, '');
241 | content = content.replace(/NS[\d]+:/g, '');
242 | content = content.replace(/xmlns:NS[\d]+=""/g, '');
243 | files[key] = '' + "\n" + content;
244 | }
245 | });
246 | },
247 |
248 | generateFilesAsync: function (options) {
249 | var requireJsPath = options.requireJsPath;
250 | var self = this;
251 | if(!options.requireJsPath) {
252 | requireJsPath = document.getElementById('requirejs') ? document.getElementById('requirejs').src : '';
253 | }
254 | if(!requireJsPath) {
255 | throw "Please add 'requirejs' to the script that includes requirejs, or specify the path as an argument";
256 | }
257 | var files = {},
258 | doneCount = this.worksheets.length,
259 | stringsCollectedCount = this.worksheets.length,
260 | workers = [];
261 |
262 | var result = {
263 | status: "Not Started",
264 | terminate: function () {
265 | for(var i = 0; i < workers.length; i++) {
266 | workers[i].terminate();
267 | }
268 | }
269 | };
270 | this._generateCorePaths(files);
271 |
272 | var done = function () {
273 | if(--doneCount === 0) {
274 | self._prepareFilesForPackaging(files);
275 | for(var i = 0; i < workers.length; i++) {
276 | workers[i].terminate();
277 | }
278 | options.success(files);
279 | }
280 | };
281 | var stringsCollected = function () {
282 | if(--stringsCollectedCount === 0) {
283 | for(var i = 0; i < workers.length; i++) {
284 | workers[i].postMessage({
285 | instruction: 'export',
286 | sharedStrings: self.sharedStrings.exportData()
287 | });
288 | }
289 | }
290 | };
291 |
292 |
293 | var worksheetWorker = function (worksheetIndex) {
294 | return {
295 | error: function () {
296 | for(var i = 0; i < workers.length; i++) {
297 | workers[i].terminate();
298 | }
299 | //message, filename, lineno
300 | options.error.apply(this, arguments);
301 | },
302 | stringsCollected: function () {
303 | stringsCollected();
304 | },
305 | finished: function (data) {
306 | files['/xl/worksheets/sheet' + (worksheetIndex + 1) + '.xml'] = {xml: data};
307 | Paths[self.worksheets[worksheetIndex].id] = 'worksheets/sheet' + (worksheetIndex + 1) + '.xml';
308 | files['/xl/worksheets/_rels/sheet' + (worksheetIndex + 1) + '.xml.rels'] = self.worksheets[worksheetIndex].relations.toXML();
309 | done();
310 | }
311 | };
312 | };
313 |
314 | for(var i = 0, l = this.worksheets.length; i < l; i++) {
315 | workers.push(
316 | this._createWorker(requireJsPath, i, worksheetWorker(i))
317 | );
318 | }
319 |
320 | return result;
321 | },
322 |
323 | _createWorker: function (requireJsPath, worksheetIndex, callbacks) {
324 | var worker = new window.Worker(require.toUrl('./WorksheetExportWorker.js'));
325 | var self = this;
326 | worker.addEventListener('error', callbacks.error);
327 | worker.addEventListener('message', function(event) {
328 | // console.log("Called back by the worker!\n", event.data);
329 | switch(event.data.status) {
330 | case "ready":
331 | worker.postMessage({
332 | instruction: 'start',
333 | data: self.worksheets[worksheetIndex].exportData()
334 | });
335 | break;
336 | case "sharedStrings":
337 | for(var i = 0; i < event.data.data.length; i++) {
338 | self.sharedStrings.addString(event.data.data[i]);
339 | }
340 | callbacks.stringsCollected();
341 | break;
342 | case "finished":
343 | callbacks.finished(event.data.data);
344 | break;
345 | }
346 | }, false);
347 | worker.postMessage({
348 | instruction: 'setup',
349 | config: {
350 | paths: {
351 | underscore: require.toUrl('underscore').slice(0, -3)
352 | },
353 | shim: {
354 | 'underscore': {
355 | exports: '_'
356 | }
357 | }
358 | },
359 | requireJsPath: requireJsPath
360 | });
361 | return worker;
362 | },
363 |
364 | generateFiles: function () {
365 | var files = {};
366 | this._generateCorePaths(files);
367 |
368 |
369 | for(var i = 0, l = this.worksheets.length; i < l; i++) {
370 | files['/xl/worksheets/sheet' + (i + 1) + '.xml'] = this.worksheets[i].toXML();
371 | Paths[this.worksheets[i].id] = 'worksheets/sheet' + (i + 1) + '.xml';
372 | files['/xl/worksheets/_rels/sheet' + (i + 1) + '.xml.rels'] = this.worksheets[i].relations.toXML();
373 | }
374 |
375 | this._prepareFilesForPackaging(files);
376 |
377 | return files;
378 | }
379 | });
380 | return Workbook;
381 | });
--------------------------------------------------------------------------------
/demo/jasmine-core/json2.js:
--------------------------------------------------------------------------------
1 | /*
2 | http://www.JSON.org/json2.js
3 | 2009-08-17
4 |
5 | Public Domain.
6 |
7 | NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
8 |
9 | See http://www.JSON.org/js.html
10 |
11 | This file creates a global JSON object containing two methods: stringify
12 | and parse.
13 |
14 | JSON.stringify(value, replacer, space)
15 | value any JavaScript value, usually an object or array.
16 |
17 | replacer an optional parameter that determines how object
18 | values are stringified for objects. It can be a
19 | function or an array of strings.
20 |
21 | space an optional parameter that specifies the indentation
22 | of nested structures. If it is omitted, the text will
23 | be packed without extra whitespace. If it is a number,
24 | it will specify the number of spaces to indent at each
25 | level. If it is a string (such as '\t' or ' '),
26 | it contains the characters used to indent at each level.
27 |
28 | This method produces a JSON text from a JavaScript value.
29 |
30 | When an object value is found, if the object contains a toJSON
31 | method, its toJSON method will be called and the result will be
32 | stringified. A toJSON method does not serialize: it returns the
33 | value represented by the name/value pair that should be serialized,
34 | or undefined if nothing should be serialized. The toJSON method
35 | will be passed the key associated with the value, and this will be
36 | bound to the value
37 |
38 | For example, this would serialize Dates as ISO strings.
39 |
40 | Date.prototype.toJSON = function (key) {
41 | function f(n) {
42 | // Format integers to have at least two digits.
43 | return n < 10 ? '0' + n : n;
44 | }
45 |
46 | return this.getUTCFullYear() + '-' +
47 | f(this.getUTCMonth() + 1) + '-' +
48 | f(this.getUTCDate()) + 'T' +
49 | f(this.getUTCHours()) + ':' +
50 | f(this.getUTCMinutes()) + ':' +
51 | f(this.getUTCSeconds()) + 'Z';
52 | };
53 |
54 | You can provide an optional replacer method. It will be passed the
55 | key and value of each member, with this bound to the containing
56 | object. The value that is returned from your method will be
57 | serialized. If your method returns undefined, then the member will
58 | be excluded from the serialization.
59 |
60 | If the replacer parameter is an array of strings, then it will be
61 | used to select the members to be serialized. It filters the results
62 | such that only members with keys listed in the replacer array are
63 | stringified.
64 |
65 | Values that do not have JSON representations, such as undefined or
66 | functions, will not be serialized. Such values in objects will be
67 | dropped; in arrays they will be replaced with null. You can use
68 | a replacer function to replace those with JSON values.
69 | JSON.stringify(undefined) returns undefined.
70 |
71 | The optional space parameter produces a stringification of the
72 | value that is filled with line breaks and indentation to make it
73 | easier to read.
74 |
75 | If the space parameter is a non-empty string, then that string will
76 | be used for indentation. If the space parameter is a number, then
77 | the indentation will be that many spaces.
78 |
79 | Example:
80 |
81 | text = JSON.stringify(['e', {pluribus: 'unum'}]);
82 | // text is '["e",{"pluribus":"unum"}]'
83 |
84 |
85 | text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
86 | // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
87 |
88 | text = JSON.stringify([new Date()], function (key, value) {
89 | return this[key] instanceof Date ?
90 | 'Date(' + this[key] + ')' : value;
91 | });
92 | // text is '["Date(---current time---)"]'
93 |
94 |
95 | JSON.parse(text, reviver)
96 | This method parses a JSON text to produce an object or array.
97 | It can throw a SyntaxError exception.
98 |
99 | The optional reviver parameter is a function that can filter and
100 | transform the results. It receives each of the keys and values,
101 | and its return value is used instead of the original value.
102 | If it returns what it received, then the structure is not modified.
103 | If it returns undefined then the member is deleted.
104 |
105 | Example:
106 |
107 | // Parse the text. Values that look like ISO date strings will
108 | // be converted to Date objects.
109 |
110 | myData = JSON.parse(text, function (key, value) {
111 | var a;
112 | if (typeof value === 'string') {
113 | a =
114 | /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
115 | if (a) {
116 | return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
117 | +a[5], +a[6]));
118 | }
119 | }
120 | return value;
121 | });
122 |
123 | myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
124 | var d;
125 | if (typeof value === 'string' &&
126 | value.slice(0, 5) === 'Date(' &&
127 | value.slice(-1) === ')') {
128 | d = new Date(value.slice(5, -1));
129 | if (d) {
130 | return d;
131 | }
132 | }
133 | return value;
134 | });
135 |
136 |
137 | This is a reference implementation. You are free to copy, modify, or
138 | redistribute.
139 |
140 | This code should be minified before deployment.
141 | See http://javascript.crockford.com/jsmin.html
142 |
143 | USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
144 | NOT CONTROL.
145 | */
146 |
147 | /*jslint evil: true */
148 |
149 | /*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
150 | call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
151 | getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
152 | lastIndex, length, parse, prototype, push, replace, slice, stringify,
153 | test, toJSON, toString, valueOf
154 | */
155 |
156 | "use strict";
157 |
158 | // Create a JSON object only if one does not already exist. We create the
159 | // methods in a closure to avoid creating global variables.
160 |
161 | if (!this.JSON) {
162 | this.JSON = {};
163 | }
164 |
165 | (function () {
166 |
167 | function f(n) {
168 | // Format integers to have at least two digits.
169 | return n < 10 ? '0' + n : n;
170 | }
171 |
172 | if (typeof Date.prototype.toJSON !== 'function') {
173 |
174 | Date.prototype.toJSON = function (key) {
175 |
176 | return isFinite(this.valueOf()) ?
177 | this.getUTCFullYear() + '-' +
178 | f(this.getUTCMonth() + 1) + '-' +
179 | f(this.getUTCDate()) + 'T' +
180 | f(this.getUTCHours()) + ':' +
181 | f(this.getUTCMinutes()) + ':' +
182 | f(this.getUTCSeconds()) + 'Z' : null;
183 | };
184 |
185 | String.prototype.toJSON =
186 | Number.prototype.toJSON =
187 | Boolean.prototype.toJSON = function (key) {
188 | return this.valueOf();
189 | };
190 | }
191 |
192 | var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
193 | escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
194 | gap,
195 | indent,
196 | meta = { // table of character substitutions
197 | '\b': '\\b',
198 | '\t': '\\t',
199 | '\n': '\\n',
200 | '\f': '\\f',
201 | '\r': '\\r',
202 | '"' : '\\"',
203 | '\\': '\\\\'
204 | },
205 | rep;
206 |
207 |
208 | function quote(string) {
209 |
210 | // If the string contains no control characters, no quote characters, and no
211 | // backslash characters, then we can safely slap some quotes around it.
212 | // Otherwise we must also replace the offending characters with safe escape
213 | // sequences.
214 |
215 | escapable.lastIndex = 0;
216 | return escapable.test(string) ?
217 | '"' + string.replace(escapable, function (a) {
218 | var c = meta[a];
219 | return typeof c === 'string' ? c :
220 | '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
221 | }) + '"' :
222 | '"' + string + '"';
223 | }
224 |
225 |
226 | function str(key, holder) {
227 | // Produce a string from holder[key].
228 |
229 | var i, // The loop counter.
230 | k, // The member key.
231 | v, // The member value.
232 | length,
233 | mind = gap,
234 | partial,
235 | value = holder[key];
236 |
237 | // If the value has a toJSON method, call it to obtain a replacement value.
238 |
239 | if (value && typeof value === 'object' &&
240 | typeof value.toJSON === 'function') {
241 | value = value.toJSON(key);
242 | }
243 |
244 | // If we were called with a replacer function, then call the replacer to
245 | // obtain a replacement value.
246 |
247 | if (typeof rep === 'function') {
248 | value = rep.call(holder, key, value);
249 | }
250 |
251 | // What happens next depends on the value's type.
252 |
253 | switch (typeof value) {
254 | case 'string':
255 | return quote(value);
256 |
257 | case 'number':
258 |
259 | // JSON numbers must be finite. Encode non-finite numbers as null.
260 |
261 | return isFinite(value) ? String(value) : 'null';
262 |
263 | case 'boolean':
264 | case 'null':
265 |
266 | // If the value is a boolean or null, convert it to a string. Note:
267 | // typeof null does not produce 'null'. The case is included here in
268 | // the remote chance that this gets fixed someday.
269 |
270 | return String(value);
271 |
272 | // If the type is 'object', we might be dealing with an object or an array or
273 | // null.
274 |
275 | case 'object':
276 |
277 | // Due to a specification blunder in ECMAScript, typeof null is 'object',
278 | // so watch out for that case.
279 |
280 | if (!value) {
281 | return 'null';
282 | }
283 |
284 | // Make an array to hold the partial results of stringifying this object value.
285 |
286 | gap += indent;
287 | partial = [];
288 |
289 | // Is the value an array?
290 |
291 | if (Object.prototype.toString.apply(value) === '[object Array]') {
292 |
293 | // The value is an array. Stringify every element. Use null as a placeholder
294 | // for non-JSON values.
295 |
296 | length = value.length;
297 | for (i = 0; i < length; i += 1) {
298 | partial[i] = str(i, value) || 'null';
299 | }
300 |
301 | // Join all of the elements together, separated with commas, and wrap them in
302 | // brackets.
303 |
304 | v = partial.length === 0 ? '[]' :
305 | gap ? '[\n' + gap +
306 | partial.join(',\n' + gap) + '\n' +
307 | mind + ']' :
308 | '[' + partial.join(',') + ']';
309 | gap = mind;
310 | return v;
311 | }
312 |
313 | // If the replacer is an array, use it to select the members to be stringified.
314 |
315 | if (rep && typeof rep === 'object') {
316 | length = rep.length;
317 | for (i = 0; i < length; i += 1) {
318 | k = rep[i];
319 | if (typeof k === 'string') {
320 | v = str(k, value);
321 | if (v) {
322 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
323 | }
324 | }
325 | }
326 | } else {
327 |
328 | // Otherwise, iterate through all of the keys in the object.
329 |
330 | for (k in value) {
331 | if (Object.hasOwnProperty.call(value, k)) {
332 | v = str(k, value);
333 | if (v) {
334 | partial.push(quote(k) + (gap ? ': ' : ':') + v);
335 | }
336 | }
337 | }
338 | }
339 |
340 | // Join all of the member texts together, separated with commas,
341 | // and wrap them in braces.
342 |
343 | v = partial.length === 0 ? '{}' :
344 | gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
345 | mind + '}' : '{' + partial.join(',') + '}';
346 | gap = mind;
347 | return v;
348 | }
349 | }
350 |
351 | // If the JSON object does not yet have a stringify method, give it one.
352 |
353 | if (typeof JSON.stringify !== 'function') {
354 | JSON.stringify = function (value, replacer, space) {
355 | // The stringify method takes a value and an optional replacer, and an optional
356 | // space parameter, and returns a JSON text. The replacer can be a function
357 | // that can replace values, or an array of strings that will select the keys.
358 | // A default replacer method can be provided. Use of the space parameter can
359 | // produce text that is more easily readable.
360 |
361 | var i;
362 | gap = '';
363 | indent = '';
364 |
365 | // If the space parameter is a number, make an indent string containing that
366 | // many spaces.
367 |
368 | if (typeof space === 'number') {
369 | for (i = 0; i < space; i += 1) {
370 | indent += ' ';
371 | }
372 |
373 | // If the space parameter is a string, it will be used as the indent string.
374 |
375 | } else if (typeof space === 'string') {
376 | indent = space;
377 | }
378 |
379 | // If there is a replacer, it must be a function or an array.
380 | // Otherwise, throw an error.
381 |
382 | rep = replacer;
383 | if (replacer && typeof replacer !== 'function' &&
384 | (typeof replacer !== 'object' ||
385 | typeof replacer.length !== 'number')) {
386 | throw new Error('JSON.stringify');
387 | }
388 |
389 | // Make a fake root object containing our value under the key of ''.
390 | // Return the result of stringifying the value.
391 |
392 | return str('', {'': value});
393 | };
394 | }
395 |
396 |
397 | // If the JSON object does not yet have a parse method, give it one.
398 |
399 | if (typeof JSON.parse !== 'function') {
400 | JSON.parse = function (text, reviver) {
401 |
402 | // The parse method takes a text and an optional reviver function, and returns
403 | // a JavaScript value if the text is a valid JSON text.
404 |
405 | var j;
406 |
407 | function walk(holder, key) {
408 |
409 | // The walk method is used to recursively walk the resulting structure so
410 | // that modifications can be made.
411 |
412 | var k, v, value = holder[key];
413 | if (value && typeof value === 'object') {
414 | for (k in value) {
415 | if (Object.hasOwnProperty.call(value, k)) {
416 | v = walk(value, k);
417 | if (v !== undefined) {
418 | value[k] = v;
419 | } else {
420 | delete value[k];
421 | }
422 | }
423 | }
424 | }
425 | return reviver.call(holder, key, value);
426 | }
427 |
428 |
429 | // Parsing happens in four stages. In the first stage, we replace certain
430 | // Unicode characters with escape sequences. JavaScript handles many characters
431 | // incorrectly, either silently deleting them, or treating them as line endings.
432 |
433 | cx.lastIndex = 0;
434 | if (cx.test(text)) {
435 | text = text.replace(cx, function (a) {
436 | return '\\u' +
437 | ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
438 | });
439 | }
440 |
441 | // In the second stage, we run the text against regular expressions that look
442 | // for non-JSON patterns. We are especially concerned with '()' and 'new'
443 | // because they can cause invocation, and '=' because it can cause mutation.
444 | // But just to be safe, we want to reject all unexpected forms.
445 |
446 | // We split the second stage into 4 regexp operations in order to work around
447 | // crippling inefficiencies in IE's and Safari's regexp engines. First we
448 | // replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
449 | // replace all simple value tokens with ']' characters. Third, we delete all
450 | // open brackets that follow a colon or comma or that begin the text. Finally,
451 | // we look to see that the remaining characters are only whitespace or ']' or
452 | // ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
453 |
454 | if (/^[\],:{}\s]*$/.
455 | test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
456 | replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
457 | replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
458 |
459 | // In the third stage we use the eval function to compile the text into a
460 | // JavaScript structure. The '{' operator is subject to a syntactic ambiguity
461 | // in JavaScript: it can begin a block or an object literal. We wrap the text
462 | // in parens to eliminate the ambiguity.
463 |
464 | j = eval('(' + text + ')');
465 |
466 | // In the optional fourth stage, we recursively walk the new structure, passing
467 | // each name/value pair to a reviver function for possible transformation.
468 |
469 | return typeof reviver === 'function' ?
470 | walk({'': j}, '') : j;
471 | }
472 |
473 | // If the text is not JSON parseable, then a SyntaxError is thrown.
474 |
475 | throw new SyntaxError('JSON.parse');
476 | };
477 | }
478 | }());
479 |
--------------------------------------------------------------------------------
/Excel/Worksheet.js:
--------------------------------------------------------------------------------
1 | /**
2 | * This module represents an excel worksheet in its basic form - no tables, charts, etc. Its purpose is
3 | * to hold data, the data's link to how it should be styled, and any links to other outside resources.
4 | *
5 | * @module Excel/Worksheet
6 | */
7 | define(['underscore', './util', './RelationshipManager'], function (_, util, RelationshipManager) {
8 | "use strict";
9 | /**
10 | * @constructor
11 | */
12 | var Worksheet = function (config) {
13 | this.relations = null;
14 | this.columnFormats = [];
15 | this.data = [];
16 | this.mergedCells = [];
17 | this.columns = [];
18 | this._headers = [];
19 | this._footers = [];
20 | this._tables = [];
21 | this._drawings = [];
22 | this._rowInstructions = {};
23 | this.initialize(config);
24 | };
25 | _.extend(Worksheet.prototype, {
26 |
27 | initialize: function (config) {
28 | config = config || {};
29 | this.name = config.name;
30 | this.id = _.uniqueId('Worksheet');
31 | this._timezoneOffset = new Date().getTimezoneOffset() * 60 * 1000;
32 | if(config.columns) {
33 | this.setColumns(config.columns);
34 | }
35 |
36 | this.relations = new RelationshipManager();
37 | },
38 |
39 | /**
40 | * Returns an object that can be consumed by a WorksheetExportWorker
41 | * @returns {Object}
42 | */
43 | exportData: function () {
44 | return {
45 | relations: this.relations.exportData(),
46 | columnFormats: this.columnFormats,
47 | data: this.data,
48 | columns: this.columns,
49 | mergedCells: this.mergedCells,
50 | _headers: this._headers,
51 | _footers: this._footers,
52 | _tables: this._tables,
53 | _rowInstructions: this._rowInstructions,
54 | name: this.name,
55 | id: this.id
56 | };
57 | },
58 |
59 | /**
60 | * Imports data - to be used while inside of a WorksheetExportWorker.
61 | * @param {Object} data
62 | */
63 | importData: function (data) {
64 | this.relations.importData(data.relations);
65 | delete data.relations;
66 | _.extend(this, data);
67 | },
68 |
69 | setSharedStringCollection: function (stringCollection) {
70 | this.sharedStrings = stringCollection;
71 | },
72 |
73 | addTable: function (table) {
74 | this._tables.push(table);
75 | this.relations.addRelation(table, 'table');
76 | },
77 |
78 | addDrawings: function (table) {
79 | this._drawings.push(table);
80 | this.relations.addRelation(table, 'drawingRelationship');
81 | },
82 |
83 | setRowInstructions: function (rowIndex, instructions) {
84 | this._rowInstructions[rowIndex] = instructions;
85 | },
86 |
87 | /**
88 | * Expects an array length of three.
89 | *
90 | * @see Excel/Worksheet compilePageDetailPiece
91 | * @see Adding headers and footers to a worksheet
92 | *
93 | * @param {Array} headers [left, center, right]
94 | */
95 | setHeader: function (headers) {
96 | if(!_.isArray(headers)) {
97 | throw "Invalid argument type - setHeader expects an array of three instructions";
98 | }
99 | this._headers = headers;
100 | },
101 |
102 | /**
103 | * Expects an array length of three.
104 | *
105 | * @see Excel/Worksheet compilePageDetailPiece
106 | * @see Adding headers and footers to a worksheet
107 | *
108 | * @param {Array} footers [left, center, right]
109 | */
110 | setFooter: function (footers) {
111 | if(!_.isArray(footers)) {
112 | throw "Invalid argument type - setFooter expects an array of three instructions";
113 | }
114 | this._footers = footers;
115 | },
116 |
117 | /**
118 | * Turns page header/footer details into the proper format for Excel.
119 | * @param {type} data
120 | * @returns {String}
121 | */
122 | compilePageDetailPackage: function (data) {
123 | data = data || "";
124 | return [
125 | "&L", this.compilePageDetailPiece(data[0] || ""),
126 | "&C", this.compilePageDetailPiece(data[1] || ""),
127 | "&R", this.compilePageDetailPiece(data[2] || "")
128 | ].join('');
129 | },
130 |
131 | /**
132 | * Turns instructions on page header/footer details into something
133 | * usable by Excel.
134 | *
135 | * @param {type} data
136 | * @returns {String|@exp;_@call;reduce}
137 | */
138 | compilePageDetailPiece: function (data) {
139 | if(_.isString(data)) {
140 | return '&"-,Regular"'.concat(data);
141 | }
142 | if(_.isObject(data) && !_.isArray(data)) {
143 | var string = "";
144 | if(data.font || data.bold) {
145 | var weighting = data.bold ? "Bold" : "Regular";
146 | string += '&"' + (data.font || '-');
147 | string += ',' + weighting + '"';
148 | } else {
149 | string += '&"-,Regular"';
150 | }
151 | if(data.underline) {
152 | string += "&U";
153 | }
154 | if(data.fontSize) {
155 | string += "&"+data.fontSize;
156 | }
157 | string += data.text;
158 |
159 | return string;
160 | }
161 |
162 | if(_.isArray(data)) {
163 | var self = this;
164 | return _.reduce(data, function (m, v) {
165 | return m.concat(self.compilePageDetailPiece(v));
166 | }, "");
167 | }
168 | },
169 |
170 | /**
171 | * Creates the header node.
172 | *
173 | * @todo implement the ability to do even/odd headers
174 | * @param {XML Doc} doc
175 | * @returns {XML Node}
176 | */
177 | exportHeader: function (doc) {
178 | var oddHeader = doc.createElement('oddHeader');
179 | oddHeader.appendChild(doc.createTextNode(this.compilePageDetailPackage(this._headers)));
180 | return oddHeader;
181 | },
182 |
183 | /**
184 | * Creates the footer node.
185 | *
186 | * @todo implement the ability to do even/odd footers
187 | * @param {XML Doc} doc
188 | * @returns {XML Node}
189 | */
190 | exportFooter: function (doc) {
191 | var oddFooter = doc.createElement('oddFooter');
192 | oddFooter.appendChild(doc.createTextNode(this.compilePageDetailPackage(this._footers)));
193 | return oddFooter;
194 | },
195 |
196 | /**
197 | * This creates some nodes ahead of time, which cuts down on generation time due to
198 | * most cell definitions being essentially the same, but having multiple nodes that need
199 | * to be created. Cloning takes less time than creation.
200 | *
201 | * @private
202 | * @param {XML Doc} doc
203 | * @returns {_L8.Anonym$0._buildCache.Anonym$2}
204 | */
205 | _buildCache: function (doc) {
206 | var numberNode = doc.createElement('c');
207 | var value = doc.createElement('v');
208 | value.appendChild(doc.createTextNode("--temp--"));
209 | numberNode.appendChild(value);
210 |
211 | var formulaNode = doc.createElement('c');
212 | var formulaValue = doc.createElement('f');
213 | formulaValue.appendChild(doc.createTextNode("--temp--"));
214 | formulaNode.appendChild(formulaValue);
215 |
216 | var stringNode = doc.createElement('c');
217 | stringNode.setAttribute('t', 's');
218 | var stringValue = doc.createElement('v');
219 | stringValue.appendChild(doc.createTextNode("--temp--"));
220 | stringNode.appendChild(stringValue);
221 |
222 |
223 | return {
224 | number: numberNode,
225 | date: numberNode,
226 | string: stringNode,
227 | formula: formulaNode
228 | };
229 | },
230 |
231 | /**
232 | * Runs through the XML document and grabs all of the strings that will
233 | * be sent to the 'shared strings' document.
234 | *
235 | * @returns {Array}
236 | */
237 | collectSharedStrings: function () {
238 | var data = this.data;
239 | var maxX = 0;
240 | var strings = {};
241 | for(var row = 0, l = data.length; row < l; row++) {
242 | var dataRow = data[row];
243 | var cellCount = dataRow.length;
244 | maxX = cellCount > maxX ? cellCount : maxX;
245 | for(var c = 0; c < cellCount; c++) {
246 | var cellValue = dataRow[c];
247 | var metadata = cellValue && cellValue.metadata || {};
248 | if (cellValue && typeof cellValue === 'object') {
249 | cellValue = cellValue.value;
250 | }
251 |
252 | if(!metadata.type) {
253 | if(typeof cellValue === 'number') {
254 | metadata.type = 'number';
255 | }
256 | }
257 | if(metadata.type === "text" || !metadata.type) {
258 | if(typeof strings[cellValue] === 'undefined') {
259 | strings[cellValue] = true;
260 | }
261 | }
262 | }
263 | }
264 | return _.keys(strings);
265 | },
266 |
267 | toXML: function () {
268 | var data = this.data;
269 | var columns = this.columns || [];
270 | var doc = util.createXmlDoc(util.schemas.spreadsheetml, 'worksheet');
271 | var worksheet = doc.documentElement;
272 | var i, l, row;
273 | worksheet.setAttribute('xmlns:r', util.schemas.relationships);
274 | worksheet.setAttribute('xmlns:mc', util.schemas.markupCompat);
275 |
276 | var maxX = 0;
277 | var sheetData = util.createElement(doc, 'sheetData');
278 |
279 | var cellCache = this._buildCache(doc);
280 |
281 | for(row = 0, l = data.length; row < l; row++) {
282 | var dataRow = data[row];
283 | var cellCount = dataRow.length;
284 | maxX = cellCount > maxX ? cellCount : maxX;
285 | var rowNode = doc.createElement('row');
286 |
287 | for(var c = 0; c < cellCount; c++) {
288 | columns[c] = columns[c] || {};
289 | var cellValue = dataRow[c];
290 | var cell, metadata = cellValue && cellValue.metadata || {};
291 |
292 | if (cellValue && typeof cellValue === 'object') {
293 | cellValue = cellValue.value;
294 | }
295 |
296 | if(!metadata.type) {
297 | if(typeof cellValue === 'number') {
298 | metadata.type = 'number';
299 | }
300 | }
301 |
302 | switch(metadata.type) {
303 | case "number":
304 | cell = cellCache.number.cloneNode(true);
305 | cell.firstChild.firstChild.nodeValue = cellValue;
306 | break;
307 | case "date":
308 | cell = cellCache.date.cloneNode(true);
309 | cell.firstChild.firstChild.nodeValue = 25569.0 + ((cellValue - this._timezoneOffset) / (60 * 60 * 24 * 1000));
310 | break;
311 | case "formula":
312 | cell = cellCache.formula.cloneNode(true);
313 | cell.firstChild.firstChild.nodeValue = cellValue;
314 | break;
315 | case "text":
316 | /*falls through*/
317 | default:
318 | var id;
319 | if(typeof this.sharedStrings.strings[cellValue] !== 'undefined') {
320 | id = this.sharedStrings.strings[cellValue];
321 | } else {
322 | id = this.sharedStrings.addString(cellValue);
323 | }
324 | cell = cellCache.string.cloneNode(true);
325 | cell.firstChild.firstChild.nodeValue = id;
326 | break;
327 | }
328 | if(metadata.style) {
329 | cell.setAttribute('s', metadata.style);
330 | }
331 | cell.setAttribute('r', util.positionToLetterRef(c + 1, row + 1));
332 | rowNode.appendChild(cell);
333 | }
334 | rowNode.setAttribute('r', row + 1);
335 |
336 | if (this._rowInstructions[row]) {
337 | var rowInst = this._rowInstructions[row];
338 |
339 | if (rowInst.height !== undefined) {
340 | rowNode.setAttribute('customHeight', '1');
341 | rowNode.setAttribute('ht', rowInst.height);
342 | }
343 |
344 | if (rowInst.style !== undefined) {
345 | rowNode.setAttribute('customFormat', '1');
346 | rowNode.setAttribute('s', rowInst.style);
347 | }
348 | }
349 |
350 | sheetData.appendChild(rowNode);
351 | }
352 |
353 | if(maxX !== 0) {
354 | worksheet.appendChild(util.createElement(doc, 'dimension', [
355 | ['ref', util.positionToLetterRef(1, 1) + ':' + util.positionToLetterRef(maxX, data.length)]
356 | ]));
357 | } else {
358 | worksheet.appendChild(util.createElement(doc, 'dimension', [
359 | ['ref', util.positionToLetterRef(1, 1)]
360 | ]));
361 | }
362 |
363 | if(this.columns.length) {
364 | worksheet.appendChild(this.exportColumns(doc));
365 | }
366 | worksheet.appendChild(sheetData);
367 |
368 | // 'mergeCells' should be written before 'headerFoot' and 'drawing' due to issue
369 | // with Microsoft Excel (2007, 2013)
370 | if (this.mergedCells.length > 0) {
371 | var mergeCells = doc.createElement('mergeCells');
372 | for (i = 0, l = this.mergedCells.length; i < l; i++) {
373 | var mergeCell = doc.createElement('mergeCell');
374 | mergeCell.setAttribute('ref', this.mergedCells[i][0] + ':' + this.mergedCells[i][1]);
375 | mergeCells.appendChild(mergeCell);
376 | }
377 | worksheet.appendChild(mergeCells);
378 | }
379 |
380 | this.exportPageSettings(doc, worksheet);
381 |
382 | if(this._headers.length > 0 || this._footers.length > 0) {
383 | var headerFooter = doc.createElement('headerFooter');
384 | if(this._headers.length > 0) {
385 | headerFooter.appendChild(this.exportHeader(doc));
386 | }
387 | if(this._footers.length > 0) {
388 | headerFooter.appendChild(this.exportFooter(doc));
389 | }
390 | worksheet.appendChild(headerFooter);
391 | }
392 |
393 | if(this._tables.length > 0) {
394 | var tables = doc.createElement('tableParts');
395 | tables.setAttribute('count', this._tables.length);
396 | for(i = 0, l = this._tables.length; i < l; i++) {
397 | var table = doc.createElement('tablePart');
398 | table.setAttribute('r:id', this.relations.getRelationshipId(this._tables[i]));
399 | tables.appendChild(table);
400 | }
401 | worksheet.appendChild(tables);
402 | }
403 |
404 | // the 'drawing' element should be written last, after 'headerFooter', 'mergeCells', etc. due
405 | // to issue with Microsoft Excel (2007, 2013)
406 | for(i = 0, l = this._drawings.length; i < l; i++) {
407 | var drawing = doc.createElement('drawing');
408 | drawing.setAttribute('r:id', this.relations.getRelationshipId(this._drawings[i]));
409 | worksheet.appendChild(drawing);
410 | }
411 | return doc;
412 | },
413 |
414 | /**
415 | *
416 | * @param {XML Doc} doc
417 | * @returns {XML Node}
418 | */
419 | exportColumns: function (doc) {
420 | var cols = util.createElement(doc, 'cols');
421 | for(var i = 0, l = this.columns.length; i < l; i++) {
422 | var cd = this.columns[i];
423 | var col = util.createElement(doc, 'col', [
424 | ['min', cd.min || i + 1],
425 | ['max', cd.max || i + 1]
426 | ]);
427 | if (cd.hidden) {
428 | col.setAttribute('hidden', 1);
429 | }
430 | if(cd.bestFit) {
431 | col.setAttribute('bestFit', 1);
432 | }
433 | if(cd.customWidth || cd.width) {
434 | col.setAttribute('customWidth', 1);
435 | }
436 | if(cd.width) {
437 | col.setAttribute('width', cd.width);
438 | } else {
439 | col.setAttribute('width', 9.140625);
440 | }
441 |
442 | cols.appendChild(col);
443 | }
444 | return cols;
445 | },
446 |
447 | /**
448 | * Sets the page settings on a worksheet node.
449 | *
450 | * @param {XML Doc} doc
451 | * @param {XML Node} worksheet
452 | * @returns {undefined}
453 | */
454 | exportPageSettings: function (doc, worksheet) {
455 |
456 | if(this._orientation) {
457 | worksheet.appendChild(util.createElement(doc, 'pageSetup', [
458 | ['orientation', this._orientation]
459 | ]));
460 | }
461 | },
462 |
463 | /**
464 | * http://www.schemacentral.com/sc/ooxml/t-ssml_ST_Orientation.html
465 | *
466 | * Can be one of 'portrait' or 'landscape'.
467 | *
468 | * @param {String} orientation
469 | * @returns {undefined}
470 | */
471 | setPageOrientation: function (orientation) {
472 | this._orientation = orientation;
473 | },
474 |
475 | /**
476 | * Expects an array of column definitions. Each column definition needs to have a width assigned to it.
477 | *
478 | * @param {Array} columns
479 | */
480 | setColumns: function (columns) {
481 | this.columns = columns;
482 | },
483 |
484 | /**
485 | * Expects an array of data to be translated into cells.
486 | *
487 | * @param {Array} data Two dimensional array - [ [A1, A2], [B1, B2] ]
488 | * @see Adding data to a worksheet
489 | */
490 | setData: function (data) {
491 | this.data = data;
492 | },
493 |
494 | /**
495 | * Merge cells in given range
496 | *
497 | * @param cell1 - A1, A2...
498 | * @param cell2 - A2, A3...
499 | */
500 | mergeCells: function(cell1, cell2) {
501 | this.mergedCells.push([cell1, cell2]);
502 | },
503 |
504 | /**
505 | * Expects an array containing an object full of column format definitions.
506 | * http://msdn.microsoft.com/en-us/library/documentformat.openxml.spreadsheet.column.aspx
507 | * bestFit
508 | * collapsed
509 | * customWidth
510 | * hidden
511 | * max
512 | * min
513 | * outlineLevel
514 | * phonetic
515 | * style
516 | * width
517 | * @param {Array} columnFormats
518 | */
519 | setColumnFormats: function (columnFormats) {
520 | this.columnFormats = columnFormats;
521 | }
522 | });
523 | return Worksheet;
524 | });
525 |
--------------------------------------------------------------------------------