├── CNAME ├── favicon.ico ├── topic ├── ReferendumLaborLaw20180131 │ ├── PetitionSheet.jpg │ ├── PetitionSheet.pdf │ ├── PetitionSheet.png │ └── PetitionSheet.css └── InitiativeNationalHolidayLaw │ ├── PetitionSheet.jpg │ ├── PetitionSheet.pdf │ ├── PetitionSheet.png │ └── PetitionSheet.css ├── css ├── PetitionSheetBase.css ├── PetitionEnvelopeBase.css └── PetitionForm.css ├── LICENSE ├── README.md ├── js ├── tw-city-selector.min.js └── PetitionSheet.js └── index.html /CNAME: -------------------------------------------------------------------------------- 1 | petition.tueeit.org.tw -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/HEAD/favicon.ico -------------------------------------------------------------------------------- /topic/ReferendumLaborLaw20180131/PetitionSheet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/HEAD/topic/ReferendumLaborLaw20180131/PetitionSheet.jpg -------------------------------------------------------------------------------- /topic/ReferendumLaborLaw20180131/PetitionSheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/HEAD/topic/ReferendumLaborLaw20180131/PetitionSheet.pdf -------------------------------------------------------------------------------- /topic/ReferendumLaborLaw20180131/PetitionSheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/HEAD/topic/ReferendumLaborLaw20180131/PetitionSheet.png -------------------------------------------------------------------------------- /topic/InitiativeNationalHolidayLaw/PetitionSheet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/HEAD/topic/InitiativeNationalHolidayLaw/PetitionSheet.jpg -------------------------------------------------------------------------------- /topic/InitiativeNationalHolidayLaw/PetitionSheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/HEAD/topic/InitiativeNationalHolidayLaw/PetitionSheet.pdf -------------------------------------------------------------------------------- /topic/InitiativeNationalHolidayLaw/PetitionSheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/HEAD/topic/InitiativeNationalHolidayLaw/PetitionSheet.png -------------------------------------------------------------------------------- /css/PetitionSheetBase.css: -------------------------------------------------------------------------------- 1 | div.sheet { 2 | height: 210mm; 3 | width: 297mm; 4 | background-size: 100% 100%; 5 | } 6 | 7 | div.id, div.year, div.month, div.date, div.province, div.province_1_circle, 8 | div.province_2_circle, div.county, div.county_1_circle, div.county_2_circle, 9 | div.district, div.district_1_circle, div.district_2_circle, 10 | div.district_3_circle, div.district_4_circle, div.village, 11 | div.village_1_circle, div.village_2_circle, div.neighbor, div.road, 12 | div.road_1_circle, div.road_2_circle, div.section, div.lane, 13 | div.alley, div.number, div.floor, div.part { 14 | position: absolute; 15 | } 16 | 17 | div.id, div.year, div.month, div.date { 18 | font-family: 'Inconsolata', monospace; 19 | } 20 | 21 | div.circle { 22 | display: none; 23 | } 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright 2018 4 | Trade Union of Electrical, Electronic, and Information in Taiwan (TUEEIT) 5 | http://www.tueeit.org.tw/ 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy of 8 | this software and associated documentation files (the "Software"), to deal in 9 | the Software without restriction, including without limitation the rights to 10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 11 | the Software, and to permit persons to whom the Software is furnished to do so, 12 | subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /css/PetitionEnvelopeBase.css: -------------------------------------------------------------------------------- 1 | div.evelope-wrapper { 2 | padding: 10px 32px; 3 | } 4 | 5 | div.envelope { 6 | background: white; 7 | position: relative; 8 | width: 210mm; 9 | height: 297mm; 10 | background-size: 100% 100%; 11 | } 12 | 13 | div.envelope_top, div.envelope_middle, div.envelope_bottom { 14 | position: absolute; 15 | margin: 0px; 16 | padding: 0px; 17 | width: 100%; 18 | height: 33%; 19 | } 20 | 21 | div.envelope_top { 22 | top: 0mm; 23 | } 24 | 25 | div.envelope_middle { 26 | border-top: 2px dashed black; 27 | border-bottom: 2px dashed black; 28 | top: 33%; 29 | } 30 | 31 | div.envelope_bottom { 32 | bottom: 0mm; 33 | } 34 | 35 | div.stamp { 36 | position: absolute; 37 | margin: 0px; 38 | padding: 0px; 39 | top: 0mm; 40 | right: 0mm; 41 | height: 40mm; 42 | width: 74mm; 43 | text-align: center; 44 | } 45 | 46 | div.sender { 47 | position: absolute; 48 | margin: 0px; 49 | padding: 0px; 50 | top: 10mm; 51 | left: 10mm; 52 | height: 40mm; 53 | width: 100mm; 54 | } 55 | 56 | span#stamp { 57 | position: absolute; 58 | border: 2px solid Gainsboro; 59 | top: 5mm; 60 | height: 30mm; 61 | width: 30mm; 62 | } 63 | 64 | span#sender_zipcode { 65 | display: block; 66 | font-family: 'Inconsolata', monospace; 67 | font-size: 20px; 68 | left: 0px; 69 | } 70 | 71 | span#sender_address { 72 | display: block; 73 | position: absolute; 74 | font-size: 20px; 75 | left: 0px; 76 | } 77 | 78 | span#sender_name { 79 | display: block; 80 | position: absolute; 81 | font-size: 20px; 82 | left: 0px; 83 | top: 70px; 84 | } 85 | 86 | div.receiver { 87 | position: absolute; 88 | margin: 0px; 89 | padding: 0px; 90 | top: 40mm; 91 | left: 60mm; 92 | height: 70mm; 93 | width: 100mm; 94 | } 95 | 96 | span#receiver_zipcode { 97 | display: block; 98 | font-family: 'Inconsolata', monospace; 99 | font-size: 28px; 100 | left: 0px; 101 | } 102 | 103 | span#receiver_address { 104 | display: block; 105 | position: absolute; 106 | font-size: 26px; 107 | left: 0px; 108 | } 109 | 110 | span#receiver_name { 111 | display: block; 112 | position: absolute; 113 | font-size: 26px; 114 | left: 0px; 115 | top: 100px; 116 | } 117 | 118 | span#steps { 119 | display: block; 120 | position: absolute; 121 | font-size: 20px; 122 | left: 50px; 123 | top: 50px; 124 | } 125 | 126 | span.important { 127 | font-weight: bold; 128 | text-decoration: underline; 129 | } 130 | 131 | span.center { 132 | width: 100%; 133 | text-align: center; 134 | } 135 | 136 | span.bottom { 137 | position: absolute; 138 | bottom: 0px; 139 | } 140 | 141 | span.top { 142 | position: absolute; 143 | top: 0px; 144 | } 145 | 146 | span.fold_notice { 147 | font-weight: bold; 148 | font-size: 14px; 149 | height: 20px; 150 | } 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 公投連署大平台 2 | 3 | ## 緣起 4 | [勞權公投](https://www.facebook.com/permalink.php?story_fbid=1969812579715740&id=1907997019230630)活動進入第二階連署,但因為[中央選舉委員會](https://www.cec.gov.tw/)不知道什麼時候才能把線上公投連署生出來,導致必須以實體方式進行連署,並需與意向表達無關的填寫格式、蒐集整理等問題奮鬥,大幅降低連署效率。 5 | 6 | 7 | [割闌尾計畫](http://appy.tw/)曾經建立線上連署器,這是我們所知的第一份實作,雖然形式仍是實體連署,但利用資訊技術降低了部份實體連署的問題,簡化了連署流程並確保了一致連署資料格式,並可以將連署書直接上傳至ibon,其發想及方便性令我們印象深刻。 8 | 9 | 割闌尾計畫的相關工具皆[開放原始碼](https://github.com/appy-tw)。 10 | 11 | 去年[時代力量](https://www.newpowerparty.tw/)再次建立了[公投專區](https://referendum.npp.vote/),並利用廣告回函的方式進一步降低寄出公投連署的門檻,但工具並沒有被釋放到公眾領域。 12 | 13 | 14 | 近來時代力量連署書格式的輸出格式發生[爭議](https://www.facebook.com/huimin1972/posts/10204575696108346),我們認為有需要建立另一個系統,直接使用中央選舉委員會所發出的連署書,進一步降低因格式相關問題導致公投連署書被剔除的風險。 15 | 16 | 又割闌尾計畫的程式架構,在架設服務上有較高的資源需求及技術門檻,因此我們決定重新做一個更輕量化的產生器,並吸收前人的經驗,讓系統在使用上更直覺方便。 17 | 18 | 19 | 我們期望這次建立的公投連署書產生工具,對往後的連署活動能有所幫助。 20 | 21 | 22 | 但更希望官方的線上連署系統趕快做出來。 23 | 24 | ## 相容性 25 | 目前確認能在以下環境運作正常: 26 | - Windows 7 Pro SP 1 + IE 11 27 | - Windows 7 Pro SP 1 + Firefox 60.0 28 | - Windows 8 + IE 11 29 | - Windows 8 + Firefox 59.0.3 30 | - Windows 8 + Chrome 66.0.3359.139 31 | - Win 10 + Edge 41.16299.371.0 32 | - Mac OS + Safari 33 | - Android 8.0.0 + Chrome 66.0.3359.139 34 | 35 | 目前確認在以下環境運作異常: 36 | - Windows 7 Pro SP 1 + Chrome 66.0.3359.158 37 | 省市、縣市、鄉鎮市區、村里及路街等圈選格偏移。 38 | - Android 8.0.0 + Firefox 59.0.2 39 | 身份證字號偏移。 40 | 41 | ## 授權 42 | 本程式由[電資工會](http://www.tueeit.org.tw/)開發維護,對非政府單位及非營利組織採用[MIT](https://github.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/blob/master/LICENSE)授權。 43 | 44 | 政府單位(尤其是[中央選舉委員會](https://www.cec.gov.tw/))及營利事業單位若有使用需求,請洽本會洽談授權事宜。 45 | 46 | ## 聲明 47 | 本程式不會蒐集、紀錄、追蹤任何個人資訊:為了連署所填寫的所有個人資訊,只在產生連署書時使用。 48 | 49 | 但電資工會無法保證其他基於本程式的衍生程式不會自行添加蒐集行為。 50 | 51 | ## 使用說明 52 | 如果要在程式中新增公投連署項目,可依照下列步驟執行(需具備處理HTML、CSS、Javascript能力),以`制定國定假日法`為例: 53 | 1. 修改[`js/PetitionSheet.js`](https://github.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/blob/master/js/PetitionSheet.js#L294)中定義的連署書收件人姓名、地址及郵遞區號。 54 | 2. 清空`topic`資料。 55 | 3. 為公投連署決定一個英文名字,並在`topic`目錄底下以這個名字建立子目錄(以下稱為**公投案目錄**)。 56 | 我們將`制定國定假日法`取名為`InitiativeNationalHolidayLaw`,並建立[`topic/InitiativeNationalHolidayLaw`](https://github.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/tree/master/topic/InitiativeNationalHolidayLaw)。 57 | 4. 將連署書掃描為圖檔,放入**公投案目錄**。 58 | 例如[`topic/InitiativeNationalHolidayLaw/PetitionSheet.jpg`](https://github.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/blob/master/topic/InitiativeNationalHolidayLaw/PetitionSheet.jpg) 59 | 5. 在**公投案目錄**底下建立`PetitionSheet.css`,用來描述連署書圖檔位置,及各填寫欄位的位置。 60 | 可參考[`topic/InitiativeNationalHolidayLaw/PetitionSheet.css`](https://github.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/blob/master/topic/InitiativeNationalHolidayLaw/PetitionSheet.css) 61 | 6. 修改`index.html`,將公投連署中英文名字加入`select#topic`的option中。 62 | 例如制定國定假日法的[option](https://github.com/tueeit/TaiwanPlebiscitePetitionSheetGenerator/blob/master/index.html#L67) 63 | 7. 利用預覽功能微調步驟3中描述的各欄位位置。 64 | 目前沒有專用的工具,建議利用瀏覽器的元件檢測功能。 65 | 66 | ## 致謝 67 | 「線上產生連署書」及「讓連署書可以直接封口當作信封寄出」等概念經過「割闌尾計畫」至「時代力量公投平台」的驗證,證實了這個方法對實體連署的幫助,並讓我們發現連署各種不合理的潛規則,能依此減少連署的阻礙。 68 | 69 | 謹此對割闌尾計畫及時代力量的努力致謝。 70 | 71 | 也感謝所有協助開發本程式的人。 72 | -------------------------------------------------------------------------------- /topic/InitiativeNationalHolidayLaw/PetitionSheet.css: -------------------------------------------------------------------------------- 1 | div.sheet { 2 | background-image: url('PetitionSheet.jpg'); 3 | } 4 | 5 | div.id { 6 | padding-left: 57.2mm; 7 | padding-top: 102mm; 8 | font-size: 26px; 9 | letter-spacing: 12px; 10 | } 11 | 12 | div.year { 13 | padding-left: 57mm; 14 | padding-top: 114mm; 15 | font-size: 26px; 16 | } 17 | 18 | div.month { 19 | padding-left: 85mm; 20 | padding-top: 114mm; 21 | font-size: 26px; 22 | } 23 | 24 | div.date { 25 | padding-left: 110mm; 26 | padding-top: 114mm; 27 | font-size: 26px; 28 | } 29 | 30 | div.province { 31 | padding-left: 60mm; 32 | padding-top: 124mm; 33 | font-size: 26px; 34 | } 35 | 36 | div.province_1_circle { 37 | padding-left: 87mm; 38 | padding-top: 123mm; 39 | font-size: 32px; 40 | } 41 | 42 | div.province_2_circle { 43 | padding-left: 95mm; 44 | padding-top: 123mm; 45 | font-size: 32px; 46 | } 47 | 48 | div.county { 49 | padding-left: 110mm; 50 | padding-top: 124mm; 51 | font-size: 26px; 52 | } 53 | 54 | div.county_1_circle { 55 | padding-left: 135mm; 56 | padding-top: 122mm; 57 | font-size: 32px; 58 | } 59 | 60 | div.county_2_circle { 61 | padding-left: 144mm; 62 | padding-top: 122mm; 63 | font-size: 32px; 64 | } 65 | 66 | div.district { 67 | padding-left: 157mm; 68 | padding-top: 123mm; 69 | font-size: 26px; 70 | } 71 | 72 | div.district_1_circle { 73 | padding-left: 184mm; 74 | padding-top: 122mm; 75 | font-size: 32px; 76 | } 77 | 78 | div.district_2_circle { 79 | padding-left: 192mm; 80 | padding-top: 122mm; 81 | font-size: 32px; 82 | } 83 | 84 | div.district_3_circle { 85 | padding-left: 204mm; 86 | padding-top: 121mm; 87 | font-size: 32px; 88 | } 89 | 90 | div.district_4_circle { 91 | padding-left: 215mm; 92 | padding-top: 121mm; 93 | font-size: 32px; 94 | } 95 | 96 | div.village { 97 | padding-left: 228mm; 98 | padding-top: 123mm; 99 | font-size: 26px; 100 | } 101 | 102 | div.village_1_circle { 103 | padding-left: 255mm; 104 | padding-top: 121mm; 105 | font-size: 32px; 106 | } 107 | 108 | div.village_2_circle { 109 | padding-left: 264mm; 110 | padding-top: 121mm; 111 | font-size: 32px; 112 | } 113 | 114 | div.neighbor { 115 | padding-left: 60mm; 116 | padding-top: 133mm; 117 | font-size: 26px; 118 | } 119 | 120 | div.road { 121 | padding-left: 100mm; 122 | padding-top: 133mm; 123 | font-size: 26px; 124 | } 125 | 126 | div.road_1_circle { 127 | padding-left: 135mm; 128 | padding-top: 131mm; 129 | font-size: 32px; 130 | } 131 | 132 | div.road_2_circle { 133 | padding-left: 144mm; 134 | padding-top: 131mm; 135 | font-size: 32px; 136 | } 137 | 138 | div.section { 139 | padding-left: 155mm; 140 | padding-top: 132mm; 141 | font-size: 26px; 142 | } 143 | 144 | div.lane { 145 | padding-left: 178mm; 146 | padding-top: 132mm; 147 | font-size: 26px; 148 | } 149 | 150 | div.alley { 151 | padding-left: 201mm; 152 | padding-top: 132mm; 153 | font-size: 26px; 154 | } 155 | 156 | div.number { 157 | padding-left: 223mm; 158 | padding-top: 131mm; 159 | font-size: 26px; 160 | } 161 | 162 | div.floor { 163 | padding-left: 243mm; 164 | padding-top: 131mm; 165 | font-size: 26px; 166 | } 167 | 168 | div.part { 169 | padding-left: 270mm; 170 | padding-top: 131mm; 171 | font-size: 26px; 172 | } 173 | -------------------------------------------------------------------------------- /topic/ReferendumLaborLaw20180131/PetitionSheet.css: -------------------------------------------------------------------------------- 1 | div.sheet { 2 | background-image: url('PetitionSheet.jpg'); 3 | } 4 | 5 | div.id { 6 | padding-left: 56.5mm; 7 | padding-top: 113mm; 8 | font-size: 26px; 9 | letter-spacing: 11px; 10 | } 11 | 12 | div.year { 13 | padding-left: 57mm; 14 | padding-top: 125mm; 15 | font-size: 26px; 16 | } 17 | 18 | div.month { 19 | padding-left: 83mm; 20 | padding-top: 125mm; 21 | font-size: 26px; 22 | } 23 | 24 | div.date { 25 | padding-left: 105mm; 26 | padding-top: 125mm; 27 | font-size: 26px; 28 | } 29 | 30 | div.province { 31 | padding-left: 60mm; 32 | padding-top: 135mm; 33 | font-size: 26px; 34 | } 35 | 36 | div.province_1_circle { 37 | padding-left: 84mm; 38 | padding-top: 133mm; 39 | font-size: 32px; 40 | } 41 | 42 | div.province_2_circle { 43 | padding-left: 93mm; 44 | padding-top: 133mm; 45 | font-size: 32px; 46 | } 47 | 48 | div.county { 49 | padding-left: 110mm; 50 | padding-top: 135mm; 51 | font-size: 26px; 52 | } 53 | 54 | div.county_1_circle { 55 | padding-left: 132mm; 56 | padding-top: 133mm; 57 | font-size: 32px; 58 | } 59 | 60 | div.county_2_circle { 61 | padding-left: 141mm; 62 | padding-top: 133mm; 63 | font-size: 32px; 64 | } 65 | 66 | div.district { 67 | padding-left: 157mm; 68 | padding-top: 135mm; 69 | font-size: 26px; 70 | } 71 | 72 | div.district_1_circle { 73 | padding-left: 181mm; 74 | padding-top: 133mm; 75 | font-size: 32px; 76 | } 77 | 78 | div.district_2_circle { 79 | padding-left: 189mm; 80 | padding-top: 133mm; 81 | font-size: 32px; 82 | } 83 | 84 | div.district_3_circle { 85 | padding-left: 201mm; 86 | padding-top: 133mm; 87 | font-size: 32px; 88 | } 89 | 90 | div.district_4_circle { 91 | padding-left: 212mm; 92 | padding-top: 133mm; 93 | font-size: 32px; 94 | } 95 | 96 | div.village { 97 | padding-left: 228mm; 98 | padding-top: 134mm; 99 | font-size: 26px; 100 | } 101 | 102 | div.village_1_circle { 103 | padding-left: 252mm; 104 | padding-top: 133mm; 105 | font-size: 32px; 106 | } 107 | 108 | div.village_2_circle { 109 | padding-left: 261mm; 110 | padding-top: 133mm; 111 | font-size: 32px; 112 | } 113 | 114 | div.neighbor { 115 | padding-left: 60mm; 116 | padding-top: 143mm; 117 | font-size: 26px; 118 | } 119 | 120 | div.road { 121 | padding-left: 100mm; 122 | padding-top: 143mm; 123 | font-size: 26px; 124 | } 125 | 126 | div.road_1_circle { 127 | padding-left: 132mm; 128 | padding-top: 141mm; 129 | font-size: 32px; 130 | } 131 | 132 | div.road_2_circle { 133 | padding-left: 141mm; 134 | padding-top: 142mm; 135 | font-size: 32px; 136 | } 137 | 138 | div.section { 139 | padding-left: 155mm; 140 | padding-top: 143mm; 141 | font-size: 26px; 142 | } 143 | 144 | div.lane { 145 | padding-left: 178mm; 146 | padding-top: 143mm; 147 | font-size: 26px; 148 | } 149 | 150 | div.alley { 151 | padding-left: 201mm; 152 | padding-top: 143mm; 153 | font-size: 26px; 154 | } 155 | 156 | div.number { 157 | padding-left: 221mm; 158 | padding-top: 143mm; 159 | font-size: 26px; 160 | } 161 | 162 | div.floor { 163 | padding-left: 243mm; 164 | padding-top: 143mm; 165 | font-size: 26px; 166 | } 167 | 168 | div.part { 169 | padding-left: 270mm; 170 | padding-top: 143mm; 171 | font-size: 26px; 172 | } 173 | -------------------------------------------------------------------------------- /css/PetitionForm.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: gray; 3 | padding: 0px; 4 | margin: 0px; 5 | } 6 | 7 | * { 8 | box-sizing: border-box; 9 | } 10 | 11 | 12 | a { 13 | color: #1474b6; 14 | font-weight: bold; 15 | } 16 | 17 | a:hover { 18 | color: #44b4ec; 19 | } 20 | 21 | 22 | div.pagehead { 23 | box-sizing: border-box; 24 | position: fixed; 25 | width: 100%; 26 | background: rgba(247,250,251,0.64); 27 | box-shadow: 0px 2px 10px rgba(0,0,0,.25); 28 | padding: 10px 20px 4px 20px; 29 | z-index: 2; 30 | } 31 | 32 | div.pagehead h3 { 33 | text-align: center; 34 | margin: 0.25em 0em; 35 | letter-spacing: 2px; 36 | } 37 | 38 | input { 39 | letter-spacing: 1px; 40 | height: 32px; 41 | padding: 0em 0.5em; 42 | border: medium solid #b0b8ba; 43 | border-radius: 4px; 44 | margin: 2px 1px; 45 | } 46 | 47 | input:focus { 48 | background:#f5da84; 49 | } 50 | 51 | select { 52 | letter-spacing: 1px; 53 | height: 32px; 54 | padding: 0em 0.5em; 55 | border: medium solid #b0b8ba; 56 | } 57 | 58 | input.name, input.id { 59 | width: 120px; 60 | } 61 | 62 | input.birthday { 63 | width: 80px; 64 | } 65 | 66 | input.address { 67 | width: 80px; 68 | } 69 | 70 | div.table { 71 | display: flex; 72 | flex-direction: column; 73 | background: rgba(247,250,251,0.95); 74 | padding: 10px 20px; 75 | border: 1px dashed #5c5c5c; 76 | border-radius: 20px; 77 | } 78 | 79 | div.person, div.mail , div.subject { 80 | display: flex; 81 | align-items: baseline; 82 | flex-wrap: wrap; 83 | } 84 | 85 | div.person div { 86 | display: flex; 87 | align-items: baseline; 88 | } 89 | 90 | 91 | div.label { 92 | display: flex; 93 | font-size: 16px; 94 | min-width: 6.25em; 95 | letter-spacing: 1px; 96 | } 97 | 98 | div.input { 99 | display: flex; 100 | align-items: baseline; 101 | width: 160px; 102 | padding: 4px 6px 4px 0px; 103 | } 104 | 105 | div.birthday { 106 | display: flex; 107 | align-items: baseline; 108 | width: 360px; 109 | padding: 4px 6px 4px 0px; 110 | } 111 | 112 | div.location { 113 | display: flex; 114 | align-items: baseline; 115 | } 116 | 117 | div.location div.label { 118 | flex-direction: column; 119 | } 120 | 121 | div.location div.label span { 122 | font-size: 12px; 123 | } 124 | 125 | div.location div.address { 126 | display: flex; 127 | align-items: baseline; 128 | max-width: 1200px; 129 | flex-wrap: wrap; 130 | padding-bottom: 6px; 131 | } 132 | 133 | div.location div.address div { 134 | display: flex; 135 | align-items: baseline; 136 | padding: 4px 6px 2px 0px; 137 | } 138 | 139 | div.subject { 140 | display: flex; 141 | align-items: baseline; 142 | } 143 | 144 | div.subject div { 145 | padding: 4px 6px 2px 0px; 146 | } 147 | 148 | div.topic { 149 | display: flex; 150 | align-items: baseline; 151 | width: 480px; 152 | } 153 | 154 | div.input span, div.location span{ 155 | font-size: 12px; 156 | padding: 0px 2px; 157 | } 158 | 159 | div.preview { 160 | padding-top: 160px; 161 | padding-bottom: 40px; 162 | height: calc(100% - 180px); 163 | overflow: scroll; 164 | z-index: -1; 165 | background: gray; 166 | width: 1280px; 167 | } 168 | 169 | @media (max-width: 1050px) { 170 | div.preview { 171 | padding-top: 240px; 172 | height: calc(100% - 280px); 173 | } 174 | } 175 | 176 | @media (max-width: 860px) { 177 | div.preview { 178 | padding-top: 280px; 179 | height: calc(100% - 320px); 180 | width: 200%; 181 | } 182 | } 183 | 184 | @media (max-width: 640px) { 185 | div.preview { 186 | padding-top: 360px; 187 | height: calc(100% - 400px); 188 | } 189 | } 190 | 191 | div.footer { 192 | position: fixed; 193 | bottom: 0px; 194 | height: 60px; 195 | width: 100%; 196 | background:rgba(247,250,251,0.95); 197 | box-shadow:0px -2px 10px rgba(0,0,0,.25); 198 | padding: 10px 20px; 199 | z-index: 2; 200 | } 201 | 202 | div.footer button { 203 | text-align: center; 204 | width: 200px; 205 | height: 32px; 206 | border-radius: 4px; 207 | margin-left: auto; 208 | margin-right: auto; 209 | cursor: pointer; 210 | color: white; 211 | background: #af191c; 212 | } 213 | 214 | div.footer button:hover { 215 | color: white; 216 | background: #e6174b; 217 | } 218 | 219 | 220 | div#note { 221 | z-index: 3; 222 | font-size: 12px; 223 | line-height: 1.4; 224 | background: rgba(247,250,251,0.64); 225 | padding: 1em 1em 1.92em; 226 | position: fixed; 227 | bottom: 0px; 228 | right: 0px; 229 | width: 360px; 230 | border-top-left-radius: 1em; 231 | } 232 | 233 | div#note ul { 234 | font-size: 12px; 235 | margin: 0px; 236 | padding: 0px 0px 0px 10px; 237 | list-style-type: none; 238 | line-height: 1.5; 239 | } -------------------------------------------------------------------------------- /js/tw-city-selector.min.js: -------------------------------------------------------------------------------- 1 | !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.TwCitySelector=e()}(this,function(){"use strict";function t(){this.elRoleName="tw-city-selector";var t=arguments[0],n=arguments.length?["el"]:null;this.options=function(){return arguments[1]&&function(t,e){var i="",n=e.length;for(t=t||{};n--;)t.hasOwnProperty(e[n])||(i+=e[n]+",");if(i)throw"缺少參數: "+i}(arguments[0],arguments[1]),function(t,e){if(!t)return e;var i;for(i in t)e[i]=t[i];return t.elCountry&&(e.elCounty=t.elCountry),t.selectedCountry&&(e.selectedCounty=t.selectedCountry),t.countryClassName&&(e.countyClassName=t.countryClassName),t.countryFiledName&&(e.countyFiledName=t.countryFiledName),e}(arguments[0],arguments[2])}(t,n,{el:null,elCounty:null,elDistrict:null,elZipcode:null,selectedCounty:null,selectedDistrict:null,only:null,showZipcode:!1,bootstrapStyle:!1,countyClassName:"county",countyFiledName:"county",districtClassName:"district",districtFieldName:"district",zipcodeClassName:"zipcode",zipcodeFieldName:"zipcode"}),function(){if(this.options.el)return this.el=i(this.options.el),this.elCounty=i(this.options.elCounty,this.el),this.elDistrict=i(this.options.elDistrict,this.el),this.elZipcode=i(this.options.elZipcode,this.el),e.call(this);var t=document.querySelectorAll("[role="+this.elRoleName+"]");return Array.prototype.forEach.call(t,function(t){var i=JSON.parse(JSON.stringify(this));return i.el=t,i.elCounty=null,i.elDistrict=null,i.elZipcode=null,i.options.only=t.getAttribute("data-only")?t.getAttribute("data-only").replace(/\s/g,"").split(","):null,i.options.selectedCounty=t.getAttribute("data-selected-county")||t.getAttribute("data-selected-country"),i.options.selectedDistrict=t.getAttribute("data-selected-district"),i.options.bootstrapStyle=null!=t.getAttribute("data-bootstrap-style"),i.options.showZipcode=null!=t.getAttribute("data-show-zipcode"),e.call(i)},this),t}.call(this)}function e(){return function(){var t=document.createDocumentFragment();if(!this.elCounty){var e=document.createElement("select");this.elCounty=e,t.appendChild(e)}if(this.elCounty.innerHTML=function(){for(var t='選擇縣市',e=function(){var t=this.options.only;return Array.isArray(t)?t.map(function(t){var e=t.indexOf("@");return-1===e?t:t.substring(0,e)}):null}.call(this),i=0,n=o.counties.length;i'+o.counties[i]+"");return t}.call(this),this.elCounty.setAttribute("class",this.options.countyClassName),this.elCounty.name=this.options.countyFiledName,!this.elDistrict){var i=document.createElement("select");this.elDistrict=i,t.appendChild(i)}if(this.elDistrict.innerHTML=n.call(this),this.elDistrict.setAttribute("class",this.options.districtClassName),this.elDistrict.name=this.options.districtFieldName,!this.elZipcode){var s=document.createElement("input");this.elZipcode=s,t.appendChild(s),this.elZipcode.style.display=this.options.showZipcode||"none",this.elZipcode.style.width="6em",this.elZipcode.readOnly=!0,this.elZipcode.type="text",this.elZipcode.placeholder="郵遞區號",this.elZipcode.name=this.options.zipcodeFieldName,this.elZipcode.setAttribute("class",this.options.zipcodeClassName),this.elZipcode.autocomplete="off"}this.el.appendChild(t)}.call(this),function(){var t=function(){var t=this.elCounty.querySelector("option:checked").dataset.index;this.elDistrict.innerHTML=n.call(this,t),this.elZipcode.value=""}.bind(this);this.elCounty.addEventListener("change",t)}.call(this),function(){var t=function(){var t=this.elDistrict.querySelector("option:checked").dataset.zipcode||"";this.elZipcode.value=t}.bind(this);this.elDistrict.addEventListener("change",t)}.call(this),function(){if(this.options.selectedCounty){var t=document.createEvent("Event");t.initEvent("change",!0,!0),this.elCounty.value=this.options.selectedCounty,this.elCounty.dispatchEvent(t)}this.options.selectedDistrict&&(this.elDistrict.value=this.options.selectedDistrict,this.elDistrict.dispatchEvent(t))}.call(this),this.options.bootstrapStyle&&function(){var t=document.createDocumentFragment();this.elCounty.setAttribute("class","form-control"),this.elDistrict.setAttribute("class","form-control"),this.elZipcode.setAttribute("class","form-control");var e=document.createElement("div");e.setAttribute("class","form-group");var i=e.cloneNode();i.appendChild(this.elCounty),t.appendChild(i);var n=e.cloneNode();n.appendChild(this.elDistrict),t.appendChild(n);var o=e.cloneNode();o.appendChild(this.elZipcode),t.appendChild(o),this.el.appendChild(t)}.call(this),this}function i(t,e){return t?e?e.querySelector(t):document.querySelector(t):null}function n(t){if(!t)return'---';for(var e='選擇區域',i=this.elCounty.value,n=function(t){var e=this.options.only;if(!Array.isArray(e))return null;var i=null;return e.forEach(function(e){if(-1!==e.indexOf(t)){var n=e.lastIndexOf("@");return-1!==n?i=e.substring(n+1).split("|"):void 0}}),i}.call(this,i),s=0,l=o.districts[t][0].length-1;s<=l;s++)n&&-1===n.indexOf(o.districts[t][0][s])||(e+='\n\t\t '+o.districts[t][0][s]+"\n\t\t ");return e}var o={counties:["臺北市","基隆市","新北市","宜蘭縣","桃園市","新竹市","新竹縣","苗栗縣","臺中市","彰化縣","南投縣","嘉義市","嘉義縣","雲林縣","臺南市","高雄市","澎湖縣","金門縣","屏東縣","臺東縣","花蓮縣","連江縣"],districts:[[["中正區","大同區","中山區","松山區","大安區","萬華區","信義區","士林區","北投區","內湖區","南港區","文山區"],["100","103","104","105","106","108","110","111","112","114","115","116"]],[["仁愛區","信義區","中正區","中山區","安樂區","暖暖區","七堵區"],["200","201","202","203","204","205","206"]],[["萬里區","金山區","板橋區","汐止區","深坑區","石碇區","瑞芳區","平溪區","雙溪區","貢寮區","新店區","坪林區","烏來區","永和區","中和區","土城區","三峽區","樹林區","鶯歌區","三重區","新莊區","泰山區","林口區","蘆洲區","五股區","八里區","淡水區","三芝區","石門區"],["207","208","220","221","222","223","224","226","227","228","231","232","233","234","235","236","237","238","239","241","242","243","244","247","248","249","251","252","253"]],[["宜蘭市","頭城鎮","礁溪鄉","壯圍鄉","員山鄉","羅東鎮","三星鄉","大同鄉","五結鄉","冬山鄉","蘇澳鎮","南澳鄉","釣魚台"],["260","261","262","263","264","265","266","267","268","269","270","272","290"]],[["中壢區","平鎮區","龍潭區","楊梅區","新屋區","觀音區","桃園區","龜山區","八德區","大溪區","復興區","大園區","蘆竹區"],["320","324","325","326","327","328","330","333","334","335","336","337","338"]],[["東區","北區","香山區"],["300","300","300"]],[["竹北市","湖口鄉","新豐鄉","新埔鎮","關西鎮","芎林鄉","寶山鄉","竹東鎮","五峰鄉","橫山鄉","尖石鄉","北埔鄉","峨眉鄉"],["302","303","304","305","306","307","308","310","311","312","313","314","315"]],[["竹南鎮","頭份市","三灣鄉","南庄鄉","獅潭鄉","後龍鎮","通霄鎮","苑裡鎮","苗栗市","造橋鄉","頭屋鄉","公館鄉","大湖鄉","泰安鄉","銅鑼鄉","三義鄉","西湖鄉","卓蘭鎮"],["350","351","352","353","354","356","357","358","360","361","362","363","364","365","366","367","368","369"]],[["中區","東區","南區","西區","北區","北屯區","西屯區","南屯區","太平區","大里區","霧峰區","烏日區","豐原區","后里區","石岡區","東勢區","和平區","新社區","潭子區","大雅區","神岡區","大肚區","沙鹿區","龍井區","梧棲區","清水區","大甲區","外埔區","大安區"],["400","401","402","403","404","406","407","408","411","412","413","414","420","421","422","423","424","426","427","428","429","432","433","434","435","436","437","438","439"]],[["彰化市","芬園鄉","花壇鄉","秀水鄉","鹿港鎮","福興鄉","線西鄉","和美鎮","伸港鄉","員林市","社頭鄉","永靖鄉","埔心鄉","溪湖鎮","大村鄉","埔鹽鄉","田中鎮","北斗鎮","田尾鄉","埤頭鄉","溪州鄉","竹塘鄉","二林鎮","大城鄉","芳苑鄉","二水鄉"],["500","502","503","504","505","506","507","508","509","510","511","512","513","514","515","516","520","521","522","523","524","525","526","527","528","530"]],[["南投市","中寮鄉","草屯鎮","國姓鄉","埔里鎮","仁愛鄉","名間鄉","集集鎮","水里鄉","魚池鄉","信義鄉","竹山鎮","鹿谷鄉"],["540","541","542","544","545","546","551","552","553","555","556","557","558"]],[["東區","西區"],["600","600"]],[["番路鄉","梅山鄉","竹崎鄉","阿里山","中埔鄉","大埔鄉","水上鄉","鹿草鄉","太保市","朴子市","東石鄉","六腳鄉","新港鄉","民雄鄉","大林鎮","溪口鄉","義竹鄉","布袋鎮"],["602","603","604","605","606","607","608","611","612","613","614","615","616","621","622","623","624","625"]],[["斗南鎮","大埤鄉","虎尾鎮","土庫鎮","褒忠鄉","東勢鄉","臺西鄉","崙背鄉","麥寮鄉","斗六市","林內鄉","古坑鄉","莿桐鄉","西螺鎮","二崙鄉","北港鎮","水林鄉","口湖鄉","四湖鄉","元長鄉"],["630","631","632","633","634","635","636","637","638","640","643","646","647","648","649","651","652","653","654","655"]],[["中西區","東區","南區","北區","安平區","安南區","永康區","歸仁區","新化區","左鎮區","玉井區","楠西區","南化區","仁德區","關廟區","龍崎區","官田區","麻豆區","佳里區","西港區","七股區","將軍區","學甲區","北門區","新營區","後壁區","白河區","東山區","六甲區","下營區","柳營區","鹽水區","善化區","大內區","山上區","新市區","安定區"],["700","701","702","704","708","709","710","711","712","713","714","715","716","717","718","719","720","721","722","723","724","725","726","727","730","731","732","733","734","735","736","737","741","742","743","744","745"]],[["新興區","前金區","苓雅區","鹽埕區","鼓山區","旗津區","前鎮區","三民區","楠梓區","小港區","左營區","仁武區","大社區","東沙群島","南沙群島","岡山區","路竹區","阿蓮區","田寮區","燕巢區","橋頭區","梓官區","彌陀區","永安區","湖內區","鳳山區","大寮區","林園區","鳥松區","大樹區","旗山區","美濃區","六龜區","內門區","杉林區","甲仙區","桃源區","那瑪夏區","茂林區","茄萣區"],["800","801","802","803","804","805","806","807","811","812","813","814","815","817","819","820","821","822","823","824","825","826","827","828","829","830","831","832","833","840","842","843","844","845","846","847","848","849","851","852"]],[["馬公市","西嶼鄉","望安鄉","七美鄉","白沙鄉","湖西鄉"],["880","881","882","883","884","885"]],[["金沙鎮","金湖鎮","金寧鄉","金城鎮","烈嶼鄉","烏坵鄉"],["890","891","892","893","894","896"]],[["屏東市","三地門鄉","霧台鄉","瑪家鄉","九如鄉","里港鄉","高樹鄉","鹽埔鄉","長治鄉","麟洛鄉","竹田鄉","內埔鄉","萬丹鄉","潮州鎮","泰武鄉","來義鄉","萬巒鄉","崁頂鄉","新埤鄉","南州鄉","林邊鄉","東港鎮","琉球鄉","佳冬鄉","新園鄉","枋寮鄉","枋山鄉","春日鄉","獅子鄉","車城鄉","牡丹鄉","恆春鎮","滿州鄉"],["900","901","902","903","904","905","906","907","908","909","911","912","913","920","921","922","923","924","925","926","927","928","929","931","932","940","941","942","943","944","945","946","947"]],[["臺東市","綠島鄉","蘭嶼鄉","延平鄉","卑南鄉","鹿野鄉","關山鎮","海端鄉","池上鄉","東河鄉","成功鎮","長濱鄉","太麻里","金峰鄉","大武鄉","達仁鄉"],["950","951","952","953","954","955","956","957","958","959","961","962","963","964","965","966"]],[["花蓮市","新城鄉","秀林鄉","吉安鄉","壽豐鄉","鳳林鎮","光復鄉","豐濱鄉","瑞穗鄉","萬榮鄉","玉里鎮","卓溪鄉","富里鄉"],["970","971","972","973","974","975","976","977","978","979","981","982","983"]],[["南竿鄉","北竿鄉","莒光鄉","東引鄉"],["209","210","211","212"]]]};return t.prototype.reset=function(){return function(){return this.elCounty.selectedIndex=0,this.elDistrict.innerHTML=n.call(this),this.elZipcode.value="",this}.call(this)},t}); 2 | //# sourceMappingURL=tw-city-selector.min.js.map 3 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 公投連署大平台 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 姓名 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 身份證字號 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 生日 47 | 48 | 49 | - 50 | - 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 地址 59 | (里鄰查詢) 60 | 61 | 62 | 63 | 64 | 65 | 66 | 鄰 67 | 68 | 69 | 70 | 段 71 | 巷 72 | 弄 73 | 74 | 75 | 號 76 | 樓之 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 連署題目 85 | 86 | 87 | 88 | 廢止民國107年1月31日公佈之「勞動基準法修訂條文」 89 | 制定「國定假日法」 90 | 91 | 92 | 93 | 94 | 連署書預覽 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | ◯ 107 | ◯ 108 | 109 | ◯ 110 | ◯ 111 | 112 | ◯ 113 | ◯ 114 | ◯ 115 | ◯ 116 | 117 | ◯ 118 | ◯ 119 | 120 | 121 | ◯ 122 | ◯ 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 連署步驟: 137 | 138 | 在連署人欄親筆簽名或蓋章,簽名或蓋章內容必須可清楚辨識姓名。 139 | 依本面黑線向後折,使連署書朝內,信封朝外。 140 | 以膠帶由外側封口,貼上郵票(8元)後寄出。 141 | *請勿使用膠水以免損毀連署書。 142 | 143 | 144 | (將線以上部份向後折) 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 請貼郵票 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | (將線以下部份向後折) 163 | 164 | 165 | 166 | 167 | 170 | 171 | 說明: 172 | 173 | 輸出pdf前請在預覽中確認資料及格式正確無誤,遇到任何問題歡迎到FB專頁或來信回報,我們會盡快處理。 174 | 所有個人資訊只在輸出連署書時一次性使用,本工具不會蒐集、紀錄。 175 | 本工具由電資工會開發,並開放原始碼,歡迎重用或協助我們讓它變得更好。 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /js/PetitionSheet.js: -------------------------------------------------------------------------------- 1 | 2 | $(document).ready(function() { 3 | new TwCitySelector({ 4 | el: "div#address", 5 | elCounty: "select#county", 6 | elDistrict: "select#district", 7 | elZipcode: "input#zipcode" 8 | }); 9 | 10 | create_data_binding(); 11 | $("button#export_pdf").click(export_pdf); 12 | change_topic($("select#topic").val()); 13 | 14 | data_validation(); 15 | }); 16 | 17 | function copy_input_to_span(id) { 18 | $("input#" + id).keyup(function() { 19 | $("span#" + id).text($(this).val()); 20 | }) 21 | } 22 | 23 | function change_topic(topic) { 24 | $("link#petition_topic_css").attr('href', 25 | 'topic/' + topic + '/PetitionSheet.css'); 26 | } 27 | 28 | function handle_county_change() { 29 | county = $(this).val(); 30 | county_name = county.substring(0, county.length - 1); 31 | county_type = county.substring(county.length - 1, county.length); 32 | 33 | if (county == '臺北市' || county == '新北市' || county == '臺中市' || 34 | county == '桃園市' || county == '臺南市' || county == '高雄市') { 35 | $("span#province").text(county_name); 36 | $("div.province_1_circle").hide(); 37 | $("div.province_2_circle").show(); 38 | $("span#county").text(''); 39 | $("div.county_1_circle").hide(); 40 | $("div.county_2_circle").hide(); 41 | return; 42 | } 43 | 44 | if (county == '金門縣' || county == '連江縣') { 45 | $("span#province").text('福建'); 46 | $("div.province_1_circle").show(); 47 | $("div.province_2_circle").hide(); 48 | $("span#county").text(county_name); 49 | $("div.county_1_circle").show(); 50 | $("div.county_2_circle").hide(); 51 | return; 52 | } 53 | 54 | $("span#province").text('臺灣'); 55 | $("div.province_1_circle").show(); 56 | $("div.province_2_circle").hide(); 57 | $("span#county").text(county_name); 58 | if (county_type == '縣') { 59 | $("div.county_1_circle").show(); 60 | $("div.county_2_circle").hide(); 61 | } else if (county_type == '市') { 62 | $("div.county_1_circle").hide(); 63 | $("div.county_2_circle").show(); 64 | } else { 65 | $("div.county_1_circle").hide(); 66 | $("div.county_2_circle").hide(); 67 | } 68 | } 69 | 70 | function handle_district_change() { 71 | district = $(this).val(); 72 | district_name = district.substring(0, district.length - 1); 73 | district_type = district.substring(district.length - 1, district.length); 74 | 75 | if (district_type == '鄉') { 76 | $("span#district").text(district_name); 77 | $("div.district_1_circle").show(); 78 | $("div.district_2_circle").hide(); 79 | $("div.district_3_circle").hide(); 80 | $("div.district_4_circle").hide(); 81 | } else if (district_type == '鎮') { 82 | $("span#district").text(district_name); 83 | $("div.district_1_circle").hide(); 84 | $("div.district_2_circle").show(); 85 | $("div.district_3_circle").hide(); 86 | $("div.district_4_circle").hide(); 87 | } else if (district_type == '市') { 88 | $("span#district").text(district_name); 89 | $("div.district_1_circle").hide(); 90 | $("div.district_2_circle").hide(); 91 | $("div.district_3_circle").show(); 92 | $("div.district_4_circle").hide(); 93 | } else if (district_type == '區') { 94 | $("span#district").text(district_name); 95 | $("div.district_1_circle").hide(); 96 | $("div.district_2_circle").hide(); 97 | $("div.district_3_circle").hide(); 98 | $("div.district_4_circle").show(); 99 | } else { 100 | $("span#district").text(district); 101 | $("div.district_1_circle").hide(); 102 | $("div.district_2_circle").hide(); 103 | $("div.district_3_circle").hide(); 104 | $("div.district_4_circle").hide(); 105 | } 106 | } 107 | 108 | function handle_road_change() { 109 | road = $(this).val(); 110 | road_name = road.substring(0, road.length - 1); 111 | road_type = road.substring(road.length - 1, road.length); 112 | 113 | if (road_type == '路') { 114 | $("span#road").text(road_name); 115 | $("div.road_1_circle").show(); 116 | $("div.road_2_circle").hide(); 117 | } else if (road_type == '街') { 118 | $("span#road").text(road_name); 119 | $("div.road_1_circle").hide(); 120 | $("div.road_2_circle").show(); 121 | } else { 122 | $("span#road").text(road); 123 | $("div.road_1_circle").hide(); 124 | $("div.road_2_circle").hide(); 125 | } 126 | } 127 | 128 | function handle_village_change() { 129 | village = $(this).val(); 130 | village_name = village.substring(0, village.length - 1); 131 | village_type = village.substring(village.length - 1, village.length); 132 | 133 | if (village_type == '村') { 134 | $("span#village").text(village_name); 135 | $("div.village_1_circle").show(); 136 | $("div.village_2_circle").hide(); 137 | } else if (village_type == '里') { 138 | $("span#village").text(village_name); 139 | $("div.village_1_circle").hide(); 140 | $("div.village_2_circle").show(); 141 | } else { 142 | $("span#village").text(village); 143 | $("div.village_1_circle").hide(); 144 | $("div.village_2_circle").hide(); 145 | } 146 | } 147 | 148 | function set_element_style(element, valid) { 149 | if (valid) { 150 | element.css("border-style", ""); 151 | element.css("border-width", ""); 152 | element.css("border-color", ""); 153 | } else { 154 | element.css("border-style", "solid"); 155 | element.css("border-width", "medium"); 156 | element.css("border-color", "#af191c"); 157 | } 158 | } 159 | 160 | function id_validation(id) { 161 | id_regexp = new RegExp('^[A-Z][12][0-9]{8}$'); 162 | if (!id_regexp.test(id)) { 163 | return false; 164 | } 165 | 166 | alpha_base = 10; 167 | alpha_order = 'ABCDEFGHJKLMNPQRSTUVXYWZIO'; 168 | // :10 :15 :20 :25 :30 :35 169 | 170 | id_alpha_value = alpha_base + alpha_order.indexOf(id.charAt(0)); 171 | id_value = [Math.floor(id_alpha_value / 10), id_alpha_value % 10]; 172 | for (i = 1; i < id.length; i++) { 173 | id_value.push(parseInt(id.charAt(i), 10)); 174 | } 175 | 176 | id_weight = [1, 9, 8, 7, 6, 5, 4, 3, 2, 1, 1]; 177 | sum = 0; 178 | for (i = 0; i < id_value.length; i++) { 179 | sum += id_value[i] * id_weight[i]; 180 | } 181 | 182 | if (sum % 10 != 0) { 183 | return false; 184 | } 185 | 186 | return true; 187 | } 188 | 189 | function birthday_validation(year_element, month_element, date_element) { 190 | birth_year = year_element.val(); 191 | birth_month = month_element.val(); 192 | birth_date = date_element.val(); 193 | 194 | input_birthday_string = birth_year + '-' + birth_month + '-' + birth_date; 195 | birthday = new Date(parseInt(birth_year, 10), parseInt(birth_month, 10) - 1, 196 | parseInt(birth_date, 10)); 197 | parsed_birthday_string = birthday.getFullYear().toString() + '-' + 198 | (birthday.getMonth() + 1).toString() + '-' + 199 | birthday.getDate().toString(); 200 | if (input_birthday_string != parsed_birthday_string) { 201 | return false; 202 | } 203 | 204 | // Check above age 18. 205 | // FIXME: Different petition has different due date. 206 | due_year = 2018; 207 | due_month = 7; 208 | due_date = 31; 209 | 210 | if (due_year - birth_year < 18) { 211 | return false; 212 | } 213 | 214 | if (due_year - birth_year == 18 && due_month < birth_month) { 215 | return false; 216 | } 217 | 218 | if (due_year - birth_year == 18 && due_month == birth_month && 219 | due_date < birth_date) { 220 | return false; 221 | } 222 | 223 | return true; 224 | } 225 | 226 | function data_validation() { 227 | result = true; 228 | 229 | element = $("select#county"); 230 | valid = element.val() != ""; 231 | set_element_style(element, valid); 232 | result = result & valid; 233 | 234 | element = $("select#district"); 235 | valid = element.val() != ""; 236 | set_element_style(element, valid); 237 | result = result & valid; 238 | 239 | element = $("input#name"); 240 | valid = element.val() != ""; 241 | set_element_style(element, valid); 242 | result = result & valid; 243 | 244 | element = $("input#village"); 245 | valid = element.val() != ""; 246 | set_element_style(element, valid); 247 | result = result & valid; 248 | 249 | element = $("input#neighbor"); 250 | valid = element.val() != ""; 251 | set_element_style(element, valid); 252 | result = result & valid; 253 | 254 | element = $("input#number"); 255 | valid = element.val() != ""; 256 | set_element_style(element, valid); 257 | result = result & valid; 258 | 259 | element = $("input#id"); 260 | valid = id_validation(element.val()); 261 | set_element_style(element, valid); 262 | result = result & valid; 263 | 264 | year_element = $("input#year"); 265 | month_element = $("input#month"); 266 | date_element = $("input#date"); 267 | valid = birthday_validation(year_element, month_element, date_element); 268 | set_element_style(year_element, valid); 269 | set_element_style(month_element, valid); 270 | set_element_style(date_element, valid); 271 | result = result & valid; 272 | 273 | return result; 274 | } 275 | 276 | function update_envelope() { 277 | $("span#sender_zipcode").text($("input#zipcode").val()); 278 | $("span#sender_name").text($("input#name").val()); 279 | sender_address = $("select#county").val() + 280 | $("select#district").val() + 281 | $("input#village").val() + 282 | $("input#neighbor").val() + '鄰' + 283 | $("input#road").val() + 284 | ($("input#section").val() == '' ? '' : $("input#section").val() + '段') + 285 | ($("input#lane").val() == '' ? '' : $("input#lane").val() + '巷') + 286 | ($("input#alley").val() == '' ? '' : $("input#alley").val() + '弄') + 287 | $("input#number").val() + '號' + 288 | ($("input#floor").val() == '' ? '' : $("input#floor").val() + '樓') + 289 | ($("input#part").val() == '' ? '' : '之' + $("input#part").val()); 290 | $("span#sender_address").text(sender_address); 291 | 292 | // FIXME: The address mapping is for "National Holiday Law" and "Labor Law" 293 | // petition only. 294 | receiver_zipcode = ''; 295 | receiver_address = ''; 296 | receiver_name = ''; 297 | 298 | county = $("select#county").val(); 299 | if (county == '基隆市') { 300 | receiver_zipcode = '20048'; 301 | receiver_address = '基隆市仁愛區仁二路81號2樓'; 302 | receiver_name = '人民民主陣線'; 303 | } else if (county == '臺北市') { 304 | receiver_zipcode = '10452'; 305 | receiver_address = '台北市中山區德惠街3巷10號1樓'; 306 | receiver_name = '台灣國際勞工協會'; 307 | } else if (county == '新北市') { 308 | receiver_zipcode = '10452'; 309 | receiver_address = '臺北市中山區民權西路27號2樓'; 310 | receiver_name = '全國教師工會總聯合會'; 311 | } else if (county == '桃園市') { 312 | receiver_zipcode = '33441'; 313 | receiver_address = '桃園市八德區介壽路一段199號3樓'; 314 | receiver_name = '桃園市產業總工會'; 315 | } else if (county == '新竹縣' || county == '新竹市' || county == '苗栗縣') { 316 | receiver_zipcode = '30268'; 317 | receiver_address = '新竹縣竹北市縣政二路606號'; 318 | receiver_name = '勞動黨'; 319 | } else if (county == '臺中市') { 320 | receiver_zipcode = '42242'; 321 | receiver_address = '台中市石岡區豐勢路梅子巷37-6號'; 322 | receiver_name = '台灣社區重建協會'; 323 | } else if (county == '彰化縣' || county == '南投縣' || county == '雲林縣') { 324 | receiver_zipcode = '63801'; 325 | receiver_address = '雲林縣麥寮鄉台塑工業園區8號福利大樓2樓'; 326 | receiver_name = '雲林縣產業總工會'; 327 | } else if (county == '嘉義縣' || county == '嘉義市') { 328 | receiver_zipcode = '24162'; 329 | receiver_address = '新北市三重區力行路1段127號2樓'; 330 | receiver_name = '新海瓦斯工會'; 331 | } else if (county == '臺南市' || county == '金門縣' || county == '澎湖縣' || 332 | county == '連江縣') { 333 | receiver_zipcode = '71752'; 334 | receiver_address = '台南市仁德區中山路136號'; 335 | receiver_name = '台南市產業總工會'; 336 | } else if (county == '高雄市' || county == '屏東縣') { 337 | receiver_zipcode = '80660'; 338 | receiver_address = '高雄市前鎮區中山三路132號4樓'; 339 | receiver_name = '高雄市產業總工會'; 340 | } else if (county == '宜蘭縣' || county == '花蓮縣' || county == '臺東縣') { 341 | receiver_zipcode = '26946'; 342 | receiver_address = '宜蘭縣冬山鄉冬山路170號'; 343 | receiver_name = '宜蘭縣產業總工會'; 344 | } 345 | 346 | $("span#receiver_zipcode").text(receiver_zipcode); 347 | $("span#receiver_address").text(receiver_address); 348 | $("span#receiver_name").text(receiver_name + ' 收'); 349 | } 350 | 351 | function form_data_change() { 352 | data_validation(); 353 | update_envelope(); 354 | } 355 | 356 | function create_data_binding() { 357 | copy_input_to_span("id") 358 | copy_input_to_span("year") 359 | copy_input_to_span("month") 360 | copy_input_to_span("date") 361 | copy_input_to_span("neighbor") 362 | copy_input_to_span("section") 363 | copy_input_to_span("lane") 364 | copy_input_to_span("alley") 365 | copy_input_to_span("number") 366 | copy_input_to_span("floor") 367 | copy_input_to_span("part") 368 | 369 | $("select#county").change(handle_county_change) 370 | $("select#district").change(handle_district_change) 371 | $("input#village").keyup(handle_village_change) 372 | $("input#road").keyup(handle_road_change) 373 | 374 | $("select#topic").change(function() { 375 | change_topic($(this).val()); 376 | }) 377 | 378 | $("div#form_table").change(form_data_change) 379 | $("div#form_table").keyup(form_data_change) 380 | } 381 | 382 | function export_pdf() { 383 | if (!data_validation()) { 384 | alert('資料不齊全或錯誤,請修正紅框標示處的資料,若為程式誤判請聯絡我們'); 385 | return; 386 | } 387 | 388 | html2canvas($("div#sheet"), { 389 | useCORS: true, 390 | allowTaint: true, 391 | taintTest: false, 392 | onrendered: function(sheet_canvas) { 393 | var sheet_img = sheet_canvas.toDataURL('image/jpeg', 1.0); 394 | 395 | html2canvas($("div#envelope"), { 396 | useCORS: true, 397 | allowTaint: true, 398 | taintTest: false, 399 | onrendered: function(envelope_canvas) { 400 | // Rotate envelop 90 degrees right. 401 | rotated_envelope_canvas = document.createElement('canvas'); 402 | rotated_envelope_canvas.width = envelope_canvas.height; 403 | rotated_envelope_canvas.height = envelope_canvas.width; 404 | rotated_envelope_ctx = rotated_envelope_canvas.getContext('2d'); 405 | rotated_envelope_ctx.rotate(90 * Math.PI / 180); 406 | rotated_envelope_ctx.drawImage( 407 | envelope_canvas, 408 | 0, 409 | -envelope_canvas.height 410 | ); 411 | var envelop_imge = rotated_envelope_canvas.toDataURL('image/jpeg', 1.0); 412 | 413 | var pdf = new jsPDF('l', 'pt', 'a4'); 414 | pdf.addImage(sheet_img, 'JPEG', 0, 0); 415 | pdf.addPage(); 416 | pdf.addImage(envelop_imge, 'JPEG', 0, 0); 417 | 418 | topic = $("select#topic option:selected").text(); 419 | pdf.save('公投連署書 - ' + topic + '(請雙面列印).pdf'); 420 | } 421 | }) 422 | } 423 | }); 424 | } 425 | --------------------------------------------------------------------------------